ZQuest Classic Coverage Report


Directory: src/
File: src/gui/jwin.cpp
Date: 2025-11-11 21:39:41
Exec Total Coverage
Lines: 115 5654 2.0%
Functions: 15 150 10.0%
Branches: 49 4423 1.1%

Line Branch Exec Source
1 #include <ctype.h>
2 #include <cstring>
3 #include "base/zapp.h"
4 #include "base/zc_alleg.h"
5 #include <allegro/internal/aintern.h>
6 #include "gui/jwin.h"
7 #include "base/zdefs.h"
8 #include "gui/editbox.h"
9 #include <iostream>
10 #include <sstream>
11 #include "base/zsys.h"
12 #include <stdio.h>
13 #include "base/util.h"
14 #include "pal.h"
15 #include "gui/tabpanel.h"
16 #include "gui/text_field.h"
17 #include "dialog/info.h"
18 #include "drawing.h"
19 using namespace util;
20 using std::string;
21 using std::istringstream;
22
23 void update_hw_screen();
24 extern int32_t zq_screen_w, zq_screen_h;
25 extern int32_t joystick_index;
26 int CheckerCol1 = 7, CheckerCol2 = 8;
27
28 int32_t abc_patternmatch = 1;
29
30 char abc_keypresses[1024] = {0};
31 void wipe_abc_keypresses() { memset(abc_keypresses, 0, 1024); }
32
33 /* these are provided for external use */
34 int32_t jwin_colors[jcMAX] =
35 {
36 0xC0C0C0,0xF0F0F0,0xD0D0D0,0x808080,0x404040,0x000000,
37 0x000080,0x00F0F0,0xFFFFFF,0xFFFFFF,0x000000,0x000080,0xFFFFFF
38 };
39
40 int32_t scheme[jcMAX] =
41 {
42 0xC0C0C0,0xF0F0F0,0xD0D0D0,0x808080,0x404040,0x000000,
43 0x000080,0x00F0F0,0xFFFFFF,0xFFFFFF,0x000000,0x000080,0xFFFFFF
44 };
45
46 int32_t jwin_pal[jcMAX] = {0};
47
48 // A pointer to this variable is used to identify the DIALOG belonging to
49 // the DialogRunner. It isn't used for anything else.
50 char newGuiMarker;
51
52 int32_t new_gui_event(DIALOG* d, guiEvent event)
53 {
54 for(int32_t i = 0; true; --d, ++i)
55 {
56 if(d->dp3 == &newGuiMarker)
57 {
58 d->d1 = i;
59 return d->proc(MSG_GUI_EVENT, d, event);
60 }
61 }
62
63 return -1;
64 }
65
66 void close_new_gui_dlg(DIALOG* d);
67
68 int32_t bound(int32_t x,int32_t low,int32_t high)
69 {
70 if(x<low) x=low;
71
72 if(x>high) x=high;
73
74 return x;
75 }
76 /*
77 float bound(float x,float low,float high)
78 {
79 if(x<low) x=low;
80 if(x>high) x=high;
81 return x;
82 }
83 */
84
85 int32_t get_selected_tab(TABPANEL* panel)
86 {
87 for(int32_t i=0; panel[i].text; ++i)
88 {
89 if((panel[i].flags&D_SELECTED)!=0)
90 return i;
91 }
92 return -1;
93 }
94
95 /* jwin_set_colors:
96 * Loads a set of colors in 0xRRGGBB or 256-color-indexed format
97 * into the current color scheme using the appropriate color depth
98 * conversions.
99 */
100 118 void jwin_set_colors(int32_t *colors)
101 {
102 118 int32_t i = 0;
103
104
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 if(bitmap_color_depth(screen) == 8)
105 {
106 // use color indices
107
2/2
✓ Branch 0 taken 118 times.
✓ Branch 1 taken 2478 times.
2596 for(; i<jcMAX; i++)
108 2478 scheme[i] = colors[i];
109 118 }
110 else
111 {
112 // 0xRRGGBB format
113 for(; i<jcMAX; i++)
114 scheme[i] = makecol(colors[i]>>16, (colors[i]>>8)&0xFF, colors[i]&0xFF);
115 }
116 118 }
117
118 /* jwin_set_dialog_color:
119 * Sets the foreground and background colors of all the objects in a dialog.
120 *
121 * Needs work!
122 */
123 void jwin_set_dialog_color(DIALOG *dialog)
124 {
125 int32_t c;
126
127 for(c=0; dialog[c].proc; c++)
128 {
129 dialog[c].fg = scheme[jcMEDDARK];
130 dialog[c].bg = scheme[jcBOX];
131 }
132 }
133
134 /* jwin_draw_frame:
135 * Draws a frame using the specified style.
136 */
137 void jwin_draw_frame(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,int32_t style)
138 {
139 optional<int> c1,c2,c3,c4;
140
141 switch(style)
142 {
143 case FR_INVIS:
144 return;
145 case FR_BOX:
146 c1 = jcLIGHT;
147 c2 = jcMEDLT;
148 c3 = jcMEDDARK;
149 c4 = jcDARK;
150 break;
151
152 case FR_INV:
153 c1 = jcDARK;
154 c2 = jcMEDDARK;
155 c3 = jcMEDLT;
156 c4 = jcLIGHT;
157 break;
158
159 case FR_DEEP:
160 c1 = jcMEDDARK;
161 c2 = jcDARK;
162 c3 = jcMEDLT;
163 c4 = jcLIGHT;
164 break;
165
166 case FR_DARK:
167 c1 = jcDARK;
168 c2 = jcMEDDARK;
169 c3 = jcMEDDARK;
170 c4 = jcDARK;
171 break;
172
173 case FR_ETCHED:
174 c1 = jcMEDDARK;
175 c2 = jcLIGHT;
176 c3 = jcMEDDARK;
177 c4 = jcLIGHT;
178 break;
179
180 case FR_MEDDARK:
181 c1 = jcMEDDARK;
182 c2 = jcBOX;
183 c3 = jcBOX;
184 c4 = jcMEDDARK;
185 break;
186
187 case FR_MENU:
188 c1 = jcLIGHT;
189 c4 = jcMEDDARK;
190 break;
191 case FR_MENU_INV:
192 c1 = jcMEDDARK;
193 c2 = jcMEDDARK;
194 c3 = jcLIGHT;
195 c4 = jcLIGHT;
196 break;
197
198 case FR_WIN:
199 default:
200 c1 = jcMEDLT;
201 c2 = jcLIGHT;
202 c3 = jcMEDDARK;
203 c4 = jcDARK;
204 break;
205 }
206
207 if(c1) c1 = scheme[*c1];
208 if(c2) c2 = scheme[*c2];
209 if(c3) c3 = scheme[*c3];
210 if(c4) c4 = scheme[*c4];
211 switch (style)
212 {
213 case FR_RED:
214 c1 = 0xE4;
215 c2 = 0xEC;
216 c3 = 0xE4;
217 c4 = 0xEC;
218 break;
219 case FR_GREEN:
220 c1 = 0xE2;
221 c2 = 0xEA;
222 c3 = 0xE2;
223 c4 = 0xEA;
224 break;
225 }
226 if(c1)
227 {
228 hline(dest, vbound(x,0,dest->w-1), vbound(y,0,dest->h-1) , vbound(x+w-2, 0,dest->w-1), *c1);
229 vline(dest, vbound(x,0,dest->w-1), vbound(y+1,0,dest->h-1), vbound(y+h-2, 0, dest->h-1), *c1);
230 }
231 if(c2)
232 {
233 hline(dest, vbound(x+1,0,dest->w-1), vbound(y+1,0,dest->h-1), vbound(x+w-3,0,dest->w-1), *c2);
234 vline(dest, vbound(x+1,0,dest->w-1), vbound(y+2,0,dest->h-1), vbound(y+h-3,0,dest->h-1), *c2);
235 }
236 if(c3)
237 {
238 hline(dest, vbound(x+1,0,dest->w-1), vbound(y+h-2,0,dest->h-1), vbound(x+w-2,0,dest->w-1), *c3);
239 vline(dest, vbound(x+w-2,0,dest->w-1), vbound(y+1,0,dest->h-1), vbound(y+h-3,0,dest->h-1), *c3);
240 }
241 if(c4)
242 {
243
244 hline(dest, vbound(x,0,dest->w-1), vbound(y+h-1,0,dest->h-1), vbound(x+w-1,0, dest->w-1), *c4);
245 vline(dest, vbound(x+w-1,0,dest->w-1), vbound(y,0,dest->h-1), vbound(y+h-2,0,dest->h-1), *c4);
246 }
247 }
248 void jwin_draw_frag_frame(BITMAP* dest, int x1, int y1, int w, int h, int fw, int fh, int style)
249 {
250 int c1,c2,c3,c4;
251
252 switch(style)
253 {
254 case FR_BOX:
255 c1 = jcLIGHT;
256 c2 = jcMEDLT;
257 c3 = jcMEDDARK;
258 c4 = jcDARK;
259 break;
260
261 case FR_INV:
262 c1 = jcDARK;
263 c2 = jcMEDDARK;
264 c3 = jcMEDLT;
265 c4 = jcLIGHT;
266 break;
267
268 case FR_DEEP:
269 c1 = jcMEDDARK;
270 c2 = jcDARK;
271 c3 = jcMEDLT;
272 c4 = jcLIGHT;
273 break;
274
275 case FR_DARK:
276 c1 = jcDARK;
277 c2 = jcMEDDARK;
278 c3 = jcMEDDARK;
279 c4 = jcDARK;
280 break;
281
282 case FR_ETCHED:
283 c1 = jcMEDDARK;
284 c2 = jcLIGHT;
285 c3 = jcMEDDARK;
286 c4 = jcLIGHT;
287 break;
288
289 case FR_MEDDARK:
290 c1 = jcMEDDARK;
291 c2 = jcBOX;
292 c3 = jcBOX;
293 c4 = jcMEDDARK;
294 break;
295
296 case FR_WIN:
297 default:
298 c1 = jcMEDLT;
299 c2 = jcLIGHT;
300 c3 = jcMEDDARK;
301 c4 = jcDARK;
302 break;
303 }
304
305 int xc = x1+fw-1;
306 int yc = y1+fh-1;
307 int x2 = x1+w-1;
308 int y2 = y1+h-1;
309
310 rectfill(dest, x1, y1, x2, yc, vc(0));
311 rectfill(dest, x1, yc, xc, y2, vc(0));
312
313 hline(dest, x1-2, y1-2, x2+2, scheme[c1]);
314 hline(dest, x1-1, y1-1, x2+1, scheme[c2]);
315
316 vline(dest, x1-2, y1-2, y2+2, scheme[c1]);
317 vline(dest, x1-1, y1-1, y2+1, scheme[c2]);
318
319 hline(dest, x1-2, y2+2, xc+2, scheme[c3]);
320 hline(dest, x1-1, y2+1, xc+1, scheme[c4]);
321
322 vline(dest, x2+2, y1-2, yc+2, scheme[c3]);
323 vline(dest, x2+1, y1-1, yc+1, scheme[c4]);
324
325 hline(dest, xc+2, yc+2, x2+2, scheme[c3]);
326 hline(dest, xc+1, yc+1, x2+1, scheme[c4]);
327
328 vline(dest, xc+2, yc+2, y2+2, scheme[c3]);
329 vline(dest, xc+1, yc+1, y2+1, scheme[c4]);
330 }
331 void jwin_draw_minimap_frame(BITMAP *dest,int x,int y,int w,int h,int scrsz,int style)
332 {
333 jwin_draw_frag_frame(dest,x,y,w,h,scrsz*8,scrsz*8,style);
334 }
335
336 /* jwin_draw_win:
337 * Draws a window -- a box with a frame.
338 */
339 void jwin_draw_win(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,int32_t frame)
340 {
341 rectfill(dest,zc_max(x,0),zc_max(y,0),zc_min(x+w-1, dest->w-1),zc_min(y+h-1, dest->h-1),scheme[jcBOX]);
342 jwin_draw_frame(dest, x, y, w, h, frame);
343 }
344
345 /* jwin_draw_button:
346 * Helper function for buttons.
347 * Draws a box with a frame that depends on "state":
348 * 0: normal border (slightly different than window border)
349 * 1: inverted border
350 * 2: dark border
351 * 3: medium dark border
352 */
353 void jwin_draw_button(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,int32_t state,int32_t type)
354 {
355 int32_t frame = FR_BOX;
356
357 if(type==1)
358 {
359 frame=FR_WIN;
360 }
361
362 switch(state)
363 {
364 case 1:
365 frame = FR_INV;
366 break;
367
368 case 2:
369 frame = FR_DARK;
370 break;
371
372 case 3:
373 frame = FR_MEDDARK;
374 break;
375 }
376
377 jwin_draw_win(dest, x, y, w, h, frame);
378 }
379
380 /* mix_value:
381 * Returns a mix of the values c1 and c2 with pos==0 being c1,
382 * pos==max being c2, pos==max/2 being half way between c1 and c2, etc.
383 */
384 int32_t mix_value(int32_t c1,int32_t c2,int32_t pos,int32_t max)
385 {
386 if(max<=0)
387 return c1;
388
389 return (c2 - c1) * pos / max + c1;
390 }
391
392 /* mix_color:
393 * Returns a mix of the colors c1 and c2 with pos==0 being c1,
394 * pos==max being c2, pos==max/2 being half way between c1 and c2, etc.
395 *
396 static int32_t mix_color(int32_t c1,int32_t c2,int32_t pos,int32_t max)
397 {
398 int32_t c;
399
400 if(bitmap_color_depth(screen) == 8)
401 c = mix_value(c1, c2, pos, max);
402 else
403 {
404 int32_t r = mix_value(getr(c1), getr(c2), pos, max);
405 int32_t g = mix_value(getg(c1), getg(c2), pos, max);
406 int32_t b = mix_value(getb(c1), getb(c2), pos, max);
407 c = makecol(r,g,b);
408 }
409
410 return c;
411 }
412 */
413
414 char *shorten_string(char *dest, char const* src, FONT *usefont, int32_t maxchars, int32_t maxwidth)
415 {
416 strncpy(dest,src,maxchars);
417 dest[maxchars-1]='\0';
418 int32_t len=(int32_t)strlen(dest);
419 int32_t width=text_length(usefont, dest);
420 dest[len]=0;
421
422 while(width>maxwidth && len>4)
423 {
424 dest[len-4] = '.';
425 dest[len-3] = '.';
426 dest[len-2] = '.';
427 dest[len-1] = 0;
428 len--;
429 width=text_length(usefont, dest);
430 }
431
432 return dest;
433 }
434
435 void jwin_draw_titlebar(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, const char *str, bool draw_button, bool helpbtn)
436 {
437 char buf[512];
438 int32_t len = (int32_t)strlen(str);
439 int32_t length = text_length(font,str);
440 int32_t height = text_height(font);
441
442 int32_t tx = x + 2;
443 int32_t ty = y + (h-height)/2;
444 PALETTE temp_pal;
445 get_palette(temp_pal);
446 dither_rect(dest, &temp_pal, x, y, x+w-1, y+h-1,
447 makecol15(temp_pal[scheme[jcTITLEL]].r,
448 temp_pal[scheme[jcTITLEL]].g,
449 temp_pal[scheme[jcTITLEL]].b),
450 makecol15(temp_pal[scheme[jcTITLER]].r,
451 temp_pal[scheme[jcTITLER]].g,
452 temp_pal[scheme[jcTITLER]].b),
453 scheme[jcTITLEL], scheme[jcTITLER]);
454
455
456 if(len>509)
457 len=509;
458
459 strncpy(buf,str,len);
460 buf[len]=0;
461
462 // this part needs work
463
464 if(length>w-20)
465 {
466 while(length>w-20 && len>1)
467 {
468 buf[len-4] = '.';
469 buf[len-3] = '.';
470 buf[len-2] = '.';
471 buf[len-1] = 0;
472 len--;
473 length = text_length(font,buf);
474 }
475 }
476
477 textout_ex(dest,font,buf,tx,ty,scheme[jcTITLEFG],-1);
478
479 if(draw_button)
480 {
481 draw_x_button(dest, x + w - 18, y+2, 0);
482 }
483
484 if(helpbtn)
485 {
486 draw_question_button(dest, x + w - (draw_button ? 36 : 18), y+2, 0);
487 }
488
489 }
490
491 void draw_question_button(BITMAP* dest, int32_t x, int32_t y, int32_t state)
492 {
493 int32_t c = scheme[jcBOXFG];
494
495 jwin_draw_button(dest,x,y,16,14,state,0);
496 x += 4 + (state?1:0);
497 y += 3 + (state?1:0);
498
499 line(dest, x+2, y+0, x+5, y+0, c);
500 line(dest, x+1, y+1, x+2, y+1, c);
501 line(dest, x+5, y+1, x+6, y+1, c);
502 line(dest, x+4, y+2, x+5, y+2, c);
503 line(dest, x+3, y+3, x+4, y+3, c);
504 line(dest, x+3, y+4, x+4, y+4, c);
505 line(dest, x+3, y+6, x+4, y+6, c);
506 line(dest, x+3, y+7, x+4, y+7, c);
507 }
508
509 void draw_x_button(BITMAP *dest, int32_t x, int32_t y, int32_t state)
510 {
511 int32_t c = scheme[jcBOXFG];
512
513 jwin_draw_button(dest,x,y,16,14,state,0);
514 x += 4 + (state?1:0);
515 y += 3 + (state?1:0);
516
517 line(dest,x, y, x+6,y+6,c);
518 line(dest,x+1,y, x+7,y+6,c);
519 line(dest,x, y+6,x+6,y, c);
520 line(dest,x+1,y+6,x+7,y, c);
521 }
522
523 void draw_arrow(BITMAP *dest, int c, int x, int y, int h, bool up, bool center)
524 {
525 if(!center)
526 x += h-1;
527 for(int i = 0; i<h; i++)
528 hline(dest, x-(up?i:h-i-1), y+i, x+(up?i:h-i-1), c);
529 }
530 void draw_arrow_horz(BITMAP *dest, int c, int x, int y, int w, bool left, bool center)
531 {
532 if(!center)
533 y += w-1;
534 for(int i = 0; i<w; i++)
535 vline(dest, x+i, y-(left?i:w-i-1), y+(left?i:w-i-1), c);
536 }
537 void draw_arrow_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, int32_t up, int32_t state)
538 {
539 int32_t c = scheme[jcDARK];
540 int32_t ah = zc_min(h/3, 5);
541 int32_t i = 0;
542
543 jwin_draw_button(dest,x,y,w,h,state,1);
544 x += w/2 - (state?0:1);
545 y += (h-ah)/2 + (state?1:0);
546
547 for(; i<ah; i++)
548 {
549 hline(dest, x-(up?i:ah-i-1), y+i, x+(up?i:ah-i-1), c);
550 }
551 }
552
553 void draw_arrow_button_horiz(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, int32_t up, int32_t state)
554 {
555 int32_t c = scheme[jcDARK];
556 int32_t aw = zc_min(w/3, 5);
557 int32_t i = 0;
558
559 jwin_draw_button(dest,x,y,w,h,state,1);
560 y += h/2 - (state?0:1);
561 x += (w-aw)/2 + (state?1:0);
562
563 for(; i<aw; i++)
564 {
565 vline(dest, x+i,y-(up?i:aw-i-1), y+(up?i:aw-i-1), c);
566 }
567 }
568
569 int32_t mouse_in_rect(int32_t x,int32_t y,int32_t w,int32_t h)
570 {
571 return ((gui_mouse_x() >= x) && (gui_mouse_y() >= y) &&
572 (gui_mouse_x() < x + w) && (gui_mouse_y() < y + h));
573 }
574
575 static int32_t jwin_do_x_button(BITMAP *dest, int32_t x, int32_t y)
576 {
577 int32_t down=0, last_draw = 0;
578
579 while(gui_mouse_b())
580 {
581 down = mouse_in_rect(x,y,16,14);
582
583 if(down!=last_draw)
584 {
585 draw_x_button(dest,x,y,down);
586 last_draw = down;
587 }
588
589 /* let other objects continue to animate */
590 broadcast_dialog_message(MSG_IDLE, 0);
591 rest(1);
592 }
593
594 if(down)
595 {
596 draw_x_button(dest,x,y,0);
597 }
598
599 return down;
600 }
601
602 /* dotted_rect:
603 * Draws a dotted rectangle, for showing an object has the input focus.
604 */
605 void dotted_rect(BITMAP *dest, int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t fg, int32_t bg)
606 {
607 int32_t x = ((x1+y1) & 1) ? 1 : 0;
608 int32_t c;
609
610 //acquire the bitmap ourselves, because locking a surface within each call is *SLOW AS BALLS* -DD
611 acquire_bitmap(dest);
612
613 for(c=x1; c<=x2; c++)
614 {
615 putpixel(dest, c, y1, (((c+y1) & 1) == x) ? fg : bg);
616 putpixel(dest, c, y2, (((c+y2) & 1) == x) ? fg : bg);
617 }
618
619 for(c=y1+1; c<y2; c++)
620 {
621 putpixel(dest, x1, c, (((c+x1) & 1) == x) ? fg : bg);
622 putpixel(dest, x2, c, (((c+x2) & 1) == x) ? fg : bg);
623 }
624
625 release_bitmap(dest);
626
627 }
628
629 static void _dotted_rect(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t fg, int32_t bg)
630 {
631 dotted_rect(screen, x1, y1, x2, y2, fg, bg);
632 }
633
634 static bool no_hline = false;
635 /* gui_textout_ln:
636 * Wrapper function for drawing text to the screen, which interprets the
637 * & character as an underbar for displaying keyboard shortcuts. Returns
638 * the width of the output string in pixels.
639 *
640 * Handles '\n' characters.
641 */
642 6 int32_t gui_textout_ln(BITMAP *bmp, FONT *f, unsigned const char *s, int32_t x, int32_t y, int32_t color, int32_t bg, int32_t pos)
643 {
644 char tmp[1024];
645 6 int32_t c = 0;
646 int32_t len;
647 6 int32_t pix_len = 0;
648 6 int32_t max_len = 0;
649 int32_t hline_pos;
650 6 int32_t xx = x;
651 6 bool is_scr = bmp == screen;
652
653
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 6 times.
21 while(s[c])
654 {
655 15 len = 0;
656 15 hline_pos = -1;
657
658
4/4
✓ Branch 0 taken 798 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 798 times.
804 for(; (s[c]) && (len<(int32_t)(sizeof(tmp)-1)); c++)
659 {
660
2/2
✓ Branch 0 taken 789 times.
✓ Branch 1 taken 9 times.
798 if(s[c] == '\n')
661 {
662 9 c++;
663 9 break;
664 }
665
2/4
✓ Branch 0 taken 789 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 789 times.
✗ Branch 3 not taken.
789 else if(!no_hline && s[c] == '&')
666 {
667 if(s[c+1] != '&')
668 hline_pos = len;
669 else
670 {
671 tmp[len++] = '&';
672 c++;
673 }
674 }
675 else
676 789 tmp[len++] = s[c];
677 789 }
678
679 15 tmp[len] = 0;
680 15 pix_len = text_length(f, tmp);
681
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 12 times.
15 if (pix_len > max_len) max_len = pix_len;
682 15 x = xx;
683
684
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if(pos==1) //center
685 {
686 x -= pix_len / 2;
687 }
688
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 else if(pos==2) //right
689 {
690 x -= pix_len;
691 }
692
693
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if(bmp)
694 {
695 15 textout_ex(bmp, f, tmp, x, y, color,bg);
696
697
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if(hline_pos >= 0)
698 {
699 int32_t i;
700 i = tmp[hline_pos];
701 tmp[hline_pos] = 0;
702 hline_pos = text_length(f, tmp);
703 tmp[0] = i;
704 tmp[1] = 0;
705 i = text_length(f, tmp);
706 hline(bmp, x+hline_pos, y+text_height(f)-gui_font_baseline, x+hline_pos+i-1, color);
707 }
708 15 }
709
710 15 y += text_height(f);
711 }
712 6 return max_len;
713 }
714
715 6 int32_t gui_textout_ln(BITMAP *bmp, unsigned const char *s, int32_t x, int32_t y, int32_t color, int32_t bg, int32_t pos)
716 {
717 6 return gui_textout_ln(bmp, font, s, x, y, color, bg, pos);
718 }
719
720 int32_t gui_text_width(FONT *f, const char *s)
721 {
722 return gui_textout_ln(NULL, f, (uint8_t*)s, 0, 0, 0, 0, 0);
723 }
724
725 6 int32_t count_newline(uint8_t *s)
726 {
727 6 int32_t cnt = 0;
728
2/2
✓ Branch 0 taken 798 times.
✓ Branch 1 taken 6 times.
804 for(int32_t q = 0; s[q] != 0; ++q)
729 {
730
2/2
✓ Branch 0 taken 789 times.
✓ Branch 1 taken 9 times.
798 if(s[q] == '\n') ++cnt;
731 798 }
732 6 return cnt;
733 }
734
735 6 int32_t gui_textheight(FONT* f, uint8_t *s)
736 {
737 6 return text_height(f) * (count_newline(s) + 1);
738 }
739
740 6 int32_t gui_textheight(uint8_t* s)
741 {
742 6 return gui_textheight(font, s);
743 }
744
745 /* typedef for the listbox callback functions */
746 typedef char *(*getfuncptr)(int32_t, int32_t *);
747
748 /* event handler that closes a dialog */
749 int32_t close_dlg()
750 {
751 return D_CLOSE;
752 }
753
754 int32_t jwin_frame_proc(int32_t msg, DIALOG *d, int32_t c)
755 {
756 //these are here to bypass compiler warnings about unused arguments
757 c=c;
758
759 if(msg == MSG_DRAW)
760 {
761 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, d->d1);
762 }
763
764 return D_O_K;
765 }
766
767 int32_t jwin_guitest_proc(int32_t msg, DIALOG *d, int32_t c)
768 {
769 //these are here to bypass compiler warnings about unused arguments
770 c=c;
771
772 if(msg == MSG_DRAW)
773 {
774 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, d->d1);
775 }
776
777 return D_O_K;
778 }
779
780 /* jwin_win_proc:
781 * Draws a box with a frame. Use dp for a title string. If dp is NULL,
782 * it won't draw a title bar. If the D_EXIT flag is set, it will also
783 * draw an "X" button on the title bar that can be used to close the
784 * dialog.
785 * If d->dp3 is non-null, it will be read as a help text string, and
786 * a ? button will be drawn, that upon clicking will display the helptext.
787 */
788 int32_t jwin_win_proc(int32_t msg, DIALOG *d, int32_t c)
789 {
790 //these are here to bypass compiler warnings about unused arguments
791 c=c;
792
793 rest(1);
794 static bool skipredraw = false;
795
796 switch(msg)
797 {
798 case MSG_DRAW:
799 if(skipredraw)
800 {
801 skipredraw = false;
802 break;
803 }
804 jwin_draw_win(screen, d->x, d->y, d->w, d->h, FR_WIN);
805
806 if(d->dp)
807 {
808 FONT *oldfont = font;
809
810 if(d->dp2)
811 {
812 font = (FONT*)d->dp2;
813 }
814
815 jwin_draw_titlebar(screen, d->x+3, d->y+3, d->w-6, 18, (char*)d->dp, d->flags & D_EXIT, d->dp3!=NULL);
816 font = oldfont;
817 }
818 break;
819
820 case MSG_WANTFOCUS:
821 if(gui_mouse_b())
822 return D_WANTFOCUS|D_REDRAW;
823 else return D_O_K;
824 case MSG_GOTFOCUS:
825 case MSG_LOSTFOCUS:
826 skipredraw = true;
827 return D_O_K;
828
829 case MSG_CLICK:
830 {
831 if((d->flags & D_EXIT) && mouse_in_rect(d->x+d->w-21, d->y+5, 16, 14))
832 {
833 if(jwin_do_x_button(screen, d->x+d->w-21, d->y+5))
834 {
835 GUI_EVENT(d, geCLOSE);
836 return D_CLOSE;
837 }
838 }
839 if(char const* helpstr = (char const*)d->dp3)
840 {
841 if(mouse_in_rect(d->x+d->w-((d->flags&D_EXIT)?39:21), d->y+5, 16, 14))
842 {
843 broadcast_dialog_message(MSG_DRAW,0);
844 InfoDialog("Info", helpstr).show();
845 }
846 }
847 }
848 break;
849 }
850
851 return D_O_K;
852 }
853
854 /* jwin_text_proc:
855 * Simple dialog procedure: draws the text string which is pointed to by dp.
856 *
857 * Handles '\n' characters.
858 */
859 6 int32_t jwin_text_proc(int32_t msg, DIALOG *d, int32_t)
860 {
861 ASSERT(d);
862
3/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 static BITMAP *dummy=create_bitmap_ex(8, 1, 1);
863
864
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 switch(msg)
865 {
866 case MSG_START:
867 {
868 6 FONT *oldfont = font;
869
870
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if(d->dp2)
871 {
872 6 font = (FONT*)d->dp2;
873 6 }
874
875 6 d->w=gui_textout_ln(dummy, (uint8_t *)d->dp, 0, 0, scheme[jcMEDDARK], -1, 0);
876 6 d->h=gui_textheight((uint8_t *)d->dp);
877
878 6 font = oldfont;
879 6 break;
880 }
881 case MSG_DRAW:
882 {
883 FONT *oldfont = font;
884
885 if(d->dp2)
886 {
887 font = (FONT*)d->dp2;
888 }
889
890 if(d->flags & D_DISABLED)
891 {
892 gui_textout_ln(screen, (uint8_t*)d->dp, d->x+1, d->y+1, scheme[jcLIGHT], scheme[jcBOX], 0);
893 d->w=gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcDISABLED_FG], -1, 0);
894 }
895 else
896 {
897 d->w=gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcBOXFG], scheme[jcBOX], 0);
898 }
899
900 font = oldfont;
901 break;
902 }
903 }
904
905 6 return D_O_K;
906 }
907
908 int32_t jwin_ctext_proc(int32_t msg, DIALOG *d, int32_t)
909 {
910 ASSERT(d);
911 static BITMAP *dummy=create_bitmap_ex(8, 320, 240);
912
913 switch(msg)
914 {
915 case MSG_START:
916 d->w=gui_textout_ln(dummy, (uint8_t *)d->dp, 0, 0, scheme[jcMEDDARK], -1, 0);
917 break;
918
919 case MSG_DRAW:
920 FONT *oldfont = font;
921
922 if(d->dp2)
923 {
924 font = (FONT*)d->dp2;
925 }
926
927 if(d->flags & D_DISABLED)
928 {
929 gui_textout_ln(screen, (uint8_t*)d->dp, d->x+1, d->y+1, scheme[jcLIGHT], scheme[jcBOX], 1);
930 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcDISABLED_FG], -1, 1);
931 }
932 else
933 {
934 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcBOXFG], scheme[jcBOX], 1);
935 }
936
937 font = oldfont;
938 break;
939 }
940
941 return D_O_K;
942 }
943
944 int32_t jwin_rtext_proc(int32_t msg, DIALOG *d, int32_t)
945 {
946 ASSERT(d);
947 static BITMAP *dummy=create_bitmap_ex(8, 1, 1);
948
949 switch(msg)
950 {
951 case MSG_START:
952 d->w=gui_textout_ln(dummy, (uint8_t *)d->dp, 0, 0, scheme[jcMEDDARK], -1, 2);
953 break;
954
955 case MSG_DRAW:
956 FONT *oldfont = font;
957
958 if(d->dp2)
959 {
960 font = (FONT*)d->dp2;
961 }
962
963 if(d->flags & D_DISABLED)
964 {
965 gui_textout_ln(screen, (uint8_t*)d->dp, d->x+1, d->y+1, scheme[jcLIGHT], scheme[jcBOX], 2);
966 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcDISABLED_FG], -1, 2);
967 }
968 else
969 {
970 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcBOXFG], scheme[jcBOX], 2);
971 }
972
973 font = oldfont;
974 break;
975 }
976
977 return D_O_K;
978 }
979
980 int32_t d_ctext2_proc(int32_t msg, DIALOG *d, int32_t c)
981 {
982 auto ret = d_ctext_proc(msg, d, c);
983 return ret;
984 }
985
986 int32_t new_text_proc(int32_t msg, DIALOG *d, int32_t c)
987 {
988 BITMAP* oldscreen = screen;
989 if(msg==MSG_DRAW)
990 {
991 if(d->flags & D_HIDDEN) return D_O_K;
992 screen = create_bitmap_ex(8,oldscreen->w,oldscreen->h);
993 clear_bitmap(screen);
994 set_clip_rect(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1);
995 }
996 int32_t ret = D_O_K;
997 int32_t w = d->w, h = d->h, x = d->x, y = d->y;
998 if(d->d2) no_hline = true;
999 switch(d->d1)
1000 {
1001 case 0:
1002 ret = jwin_text_proc(msg, d, c);
1003 break;
1004 case 1:
1005 d->x += d->w/2;
1006 ret = jwin_ctext_proc(msg, d, c);
1007 break;
1008 case 2:
1009 d->x += d->w - 1;
1010 ret = jwin_rtext_proc(msg, d, c);
1011 break;
1012 }
1013 no_hline = false;
1014 d->w = w;
1015 d->h = h;
1016 d->x = x;
1017 d->y = y;
1018 if(msg==MSG_DRAW)
1019 {
1020 masked_blit(screen, oldscreen, d->x, d->y, d->x, d->y, d->w, d->h);
1021 destroy_bitmap(screen);
1022 screen = oldscreen;
1023 }
1024 if(msg==MSG_WANTFOCUS && gui_mouse_b())
1025 ret |= D_WANTFOCUS|D_REDRAW;
1026 return ret;
1027 }
1028
1029 /* draw_text_button:
1030 * Helper for jwin_button_proc.
1031 */
1032 void jwin_draw_text_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, const char *str, int32_t flags, bool show_dotted_rect)
1033 {
1034 int32_t g = (flags & D_SELECTED) ? 1 : 0;
1035
1036 if(flags & D_SELECTED)
1037 {
1038 jwin_draw_button(dest, x, y, w, h, 2, 0);
1039 flags &= ~D_DISABLED;
1040 }
1041 else if(!(flags & D_GOTFOCUS))
1042 jwin_draw_button(dest, x, y, w, h, 0, 0);
1043 else
1044 {
1045 rect(dest, x, y, x+w-1, y+h-1, scheme[jcDARK]);
1046 jwin_draw_button(dest, x+1, y+1, w-2, h-2, 0, 0);
1047 }
1048
1049 bool drawstring = true;
1050 if(str[1]==0 && byte(str[0]) >= 0x80)
1051 {
1052 drawstring = false;
1053 int col = jwin_pal[(flags & D_DISABLED) ? jcLIGHT : jcBOXFG];
1054 int aw = w/4, ah = h/4;
1055 int woff = (aw/2)+1, hoff = (ah/2)+1;
1056 int x1 = x+w/2, x2 = x+(w-aw)/2;
1057 int y1 = y+(h-aw)/2, y2 = y+h/2;
1058 switch(byte(str[0]))
1059 {
1060 case 0x88:
1061 draw_arrow(dest, col, x1, y1, ah, true, true);
1062 break;
1063 case 0x89:
1064 draw_arrow(dest, col, x1, y1, ah, false, true);
1065 break;
1066 case 0x8A:
1067 draw_arrow_horz(dest, col, x2, y2, aw, true, true);
1068 break;
1069 case 0x8B:
1070 draw_arrow_horz(dest, col, x2, y2, aw, false, true);
1071 break;
1072 case 0x98:
1073 draw_arrow(dest, col, x1, y1-hoff, ah, false, true);
1074 draw_arrow(dest, col, x1, y1+hoff, ah, true, true);
1075 break;
1076 case 0x99:
1077 draw_arrow(dest, col, x1, y1-hoff, ah, true, true);
1078 draw_arrow(dest, col, x1, y1+hoff, ah, false, true);
1079 break;
1080 case 0x9A:
1081 draw_arrow_horz(dest, col, x2-woff, y2, aw, false, true);
1082 draw_arrow_horz(dest, col, x2+woff, y2, aw, true, true);
1083 break;
1084 case 0x9B:
1085 draw_arrow_horz(dest, col, x2-woff, y2, aw, true, true);
1086 draw_arrow_horz(dest, col, x2+woff, y2, aw, false, true);
1087 break;
1088 default: drawstring = true;
1089 }
1090 }
1091 if(drawstring)
1092 {
1093 if(!(flags & D_DISABLED))
1094 gui_textout_ex(dest, str, x+w/2+g, y+(h-text_height(font))/2+g, scheme[jcBOXFG], -1, TRUE);
1095 else
1096 {
1097 gui_textout_ex(dest, str, x+w/2+1,y+(h-text_height(font))/2+1, scheme[jcLIGHT], -1, TRUE);
1098 gui_textout_ex(dest, str, x+w/2, y+(h-text_height(font))/2, scheme[jcDISABLED_FG], -1, TRUE);
1099 }
1100 }
1101
1102 if(show_dotted_rect&&(flags & D_GOTFOCUS))
1103 dotted_rect(dest, x+4, y+4, x+w-5, y+h-5, scheme[jcDARK], scheme[jcBOX]);
1104 }
1105
1106 int icon_proportion(int icon,int s1,int s2)
1107 {
1108 int sz = round(sqrt(zc_min(s1,s2))*1.25);
1109 switch(icon)
1110 {
1111 case BTNICON_STOPSQUARE:
1112 sz += 4;
1113 break;
1114 case BTNICON_PLUS:
1115 case BTNICON_MINUS:
1116 sz += 4;
1117 break;
1118 }
1119 return sz;
1120 }
1121 void jwin_draw_icon_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, int icon, int32_t flags, bool show_dotted_rect)
1122 {
1123 int32_t g = (flags & D_SELECTED) ? 1 : 0;
1124
1125 if(flags & D_SELECTED)
1126 jwin_draw_button(dest, x, y, w, h, 2, 0);
1127 else if(!(flags & D_GOTFOCUS))
1128 jwin_draw_button(dest, x, y, w, h, 0, 0);
1129 else
1130 {
1131 rect(dest, x, y, x+w-1, y+h-1, scheme[jcDARK]);
1132 jwin_draw_button(dest, x+1, y+1, w-2, h-2, 0, 0);
1133 }
1134
1135 int col = jwin_pal[(flags & D_DISABLED) ? jcLIGHT : jcBOXFG];
1136 jwin_draw_icon(dest,x+w/2,y+h/2,col,icon,icon_proportion(icon,w,h),true);
1137
1138 if(show_dotted_rect&&(flags & D_GOTFOCUS))
1139 dotted_rect(dest, x+4, y+4, x+w-5, y+h-5, scheme[jcDARK], scheme[jcBOX]);
1140 }
1141 void jwin_draw_icon(BITMAP *dest, int x, int y, int col, int icon, int asz, bool center)
1142 {
1143 jwin_draw_icon(dest,x,y,col,icon,asz,asz,center);
1144 }
1145 void jwin_draw_icon(BITMAP *dest, int x, int y, int col, int icon, int aw, int ah, bool center)
1146 {
1147 int w2 = aw, h2 = ah;
1148 int sz = zc_min(aw,ah);
1149 switch(icon)
1150 {
1151 case BTNICON_ARROW_LEFT2:
1152 case BTNICON_ARROW_RIGHT2:
1153 aw *= 2;
1154 ah = aw*2-1;
1155 break;
1156 case BTNICON_ARROW_LEFT3:
1157 case BTNICON_ARROW_RIGHT3:
1158 aw *= 3;
1159 ah = aw*2-1;
1160 break;
1161 case BTNICON_ARROW_UP:
1162 case BTNICON_ARROW_DOWN:
1163 case BTNICON_CONTRACT_VERT:
1164 case BTNICON_EXPAND_VERT:
1165 aw = ah*2-1;
1166 break;
1167 case BTNICON_ARROW_LEFT:
1168 case BTNICON_ARROW_RIGHT:
1169 case BTNICON_CONTRACT_HORZ:
1170 case BTNICON_EXPAND_HORZ:
1171 ah = aw*2-1;
1172 break;
1173 case BTNICON_STOPSQUARE:
1174 aw = ah = sz;
1175 break;
1176 case BTNICON_PLUS:
1177 if(!(sz%2)) ++sz;
1178 aw = ah = w2 = h2 = sz;
1179 w2 /= 3;
1180 h2 /= 3;
1181 if(!(h2%2)) ++h2;
1182 if(!(w2%2)) ++w2;
1183 break;
1184 case BTNICON_MINUS:
1185 if(!(sz%2)) ++sz;
1186 aw = ah = w2 = h2 = sz;
1187 h2 /= 3;
1188 if(!(h2%2)) ++h2;
1189 break;
1190 }
1191 int woff = (aw/2)+1, hoff = (ah/2)+1;
1192 int cx = center ? (x-aw/2) : x,
1193 cy = center ? (y-ah/2) : y;
1194 switch(icon)
1195 {
1196 case BTNICON_ARROW_UP:
1197 draw_arrow(dest, col, x, cy, ah, true, center);
1198 break;
1199 case BTNICON_ARROW_DOWN:
1200 draw_arrow(dest, col, x, cy, ah, false, center);
1201 break;
1202 case BTNICON_ARROW_LEFT:
1203 draw_arrow_horz(dest, col, cx, y, aw, true, center);
1204 break;
1205 case BTNICON_ARROW_RIGHT:
1206 draw_arrow_horz(dest, col, cx, y, aw, false, center);
1207 break;
1208 case BTNICON_CONTRACT_VERT:
1209 draw_arrow(dest, col, x, cy-hoff, ah, false, center);
1210 draw_arrow(dest, col, x, cy+hoff, ah, true, center);
1211 break;
1212 case BTNICON_EXPAND_VERT:
1213 draw_arrow(dest, col, x, cy-hoff, ah, true, center);
1214 draw_arrow(dest, col, x, cy+hoff, ah, false, center);
1215 break;
1216 case BTNICON_CONTRACT_HORZ:
1217 draw_arrow_horz(dest, col, cx-woff, y, aw, false, center);
1218 draw_arrow_horz(dest, col, cx+woff, y, aw, true, center);
1219 break;
1220 case BTNICON_EXPAND_HORZ:
1221 draw_arrow_horz(dest, col, cx-woff, y, aw, true, center);
1222 draw_arrow_horz(dest, col, cx+woff, y, aw, false, center);
1223 break;
1224 case BTNICON_ARROW_LEFT2:
1225 draw_arrow_horz(dest, col, cx, y, w2, true, center);
1226 draw_arrow_horz(dest, col, cx+w2, y, w2, true, center);
1227 break;
1228 case BTNICON_ARROW_LEFT3:
1229 draw_arrow_horz(dest, col, cx, y, w2, true, center);
1230 draw_arrow_horz(dest, col, cx+w2, y, w2, true, center);
1231 draw_arrow_horz(dest, col, cx+w2*2, y, w2, true, center);
1232 break;
1233 case BTNICON_ARROW_RIGHT2:
1234 draw_arrow_horz(dest, col, cx, y, w2, false, center);
1235 draw_arrow_horz(dest, col, cx+w2, y, w2, false, center);
1236 break;
1237 case BTNICON_ARROW_RIGHT3:
1238 draw_arrow_horz(dest, col, cx, y, w2, false, center);
1239 draw_arrow_horz(dest, col, cx+w2, y, w2, false, center);
1240 draw_arrow_horz(dest, col, cx+w2*2, y, w2, false, center);
1241 break;
1242 case BTNICON_STOPSQUARE:
1243 rectfill(dest, cx, cy, cx+aw-1, cy+ah-1, col);
1244 break;
1245 case BTNICON_MINUS:
1246 rectfill(dest, cx, cy+(ah/2)-(h2/2), cx+aw-1, cy+(ah/2)+(h2/2), col);
1247 break;
1248 case BTNICON_PLUS:
1249 rectfill(dest, cx, cy+(ah/2)-(h2/2), cx+aw-1, cy+(ah/2)+(h2/2), col);
1250 rectfill(dest, cx+(aw/2)-(w2/2), cy, cx+(aw/2)+(w2/2), cy+ah-1, col);
1251 break;
1252 }
1253 }
1254 /* draw_graphics_button:
1255 * Helper for jwin_button_proc.
1256 */
1257 void jwin_draw_graphics_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, BITMAP *bmp, BITMAP *bmp2, int32_t flags, bool show_dotted_rect, bool overlay)
1258 {
1259 int32_t g = (flags & D_SELECTED) ? 1 : 0;
1260
1261 if(flags & D_SELECTED)
1262 jwin_draw_button(dest, x, y, w, h, 2, 0);
1263 else if(!(flags & D_GOTFOCUS))
1264 jwin_draw_button(dest, x, y, w, h, 0, 0);
1265 else
1266 {
1267 rect(dest, x, y, x+w-1, y+h-1, scheme[jcDARK]);
1268 jwin_draw_button(dest, x+1, y+1, w-2, h-2, 0, 0);
1269 }
1270
1271 if(!(flags & D_DISABLED))
1272 {
1273 // gui_textout_ex(dest, str, x+w/2+g, y+h/2-text_height(font)/2+g, scheme[jcBOXFG], -1, TRUE);
1274 if(bmp!=NULL)
1275 {
1276 if(overlay)
1277 {
1278 masked_blit(bmp, dest, 0, 0, x+w/2-bmp->w/2+g, y+h/2-bmp->h/2+g, bmp->h, bmp->w);
1279 }
1280 else
1281 {
1282 blit(bmp, dest, 0, 0, x+w/2-bmp->w/2+g, y+h/2-bmp->h/2+g, bmp->h, bmp->w);
1283 }
1284 }
1285 }
1286 else
1287 {
1288 // gui_textout_ex(dest, str, x+w/2+1,y+h/2-text_height(font)/2+1, scheme[jcLIGHT], -1, TRUE);
1289 // gui_textout_ex(dest, str, x+w/2, y+h/2-text_height(font)/2, scheme[jcMEDDARK], -1, TRUE);
1290 if(bmp2!=NULL)
1291 {
1292 if(overlay)
1293 {
1294 masked_blit(bmp2, dest, 0, 0, x+w/2-bmp2->w/2+g, y+h/2-bmp2->h/2+g, bmp2->h, bmp2->w);
1295 }
1296 else
1297 {
1298 blit(bmp2, dest, 0, 0, x+w/2-bmp2->w/2+g, y+h/2-bmp2->h/2+g, bmp2->h, bmp2->w);
1299 }
1300 }
1301 }
1302
1303 if(show_dotted_rect&&(flags & D_GOTFOCUS))
1304 dotted_rect(dest, x+4, y+4, x+w-5, y+h-5, scheme[jcDARK], scheme[jcBOX]);
1305 }
1306
1307 /* jwin_button_proc:
1308 * A button object (the dp field points to the text string). This object
1309 * can be selected by clicking on it with the mouse or by pressing its
1310 * keyboard shortcut. If the D_EXIT flag is set, selecting it will close
1311 * the dialog, otherwise it will toggle on and off.
1312 */
1313 int32_t jwin_button_proc(int32_t msg, DIALOG *d, int32_t)
1314 {
1315 int32_t down=0;
1316 int32_t selected=(d->flags&D_SELECTED)?1:0;
1317 int32_t disabled=(d->flags&D_DISABLED)?1:0;
1318 int32_t last_draw;
1319
1320 switch(msg)
1321 {
1322 case MSG_DRAW:
1323 {
1324 FONT *oldfont = font;
1325
1326 if(d->dp2)
1327 {
1328 font = (FONT*)d->dp2;
1329 }
1330
1331 jwin_draw_text_button(screen, d->x, d->y, d->w, d->h, (char*)d->dp, d->flags, true);
1332 font = oldfont;
1333 }
1334 break;
1335
1336 case MSG_WANTFOCUS:
1337 return D_WANTFOCUS;
1338
1339 case MSG_KEY:
1340 if(disabled) break;
1341 /* close dialog? */
1342 if(d->flags & D_EXIT)
1343 {
1344 return D_CLOSE;
1345 }
1346 if(d->d2 == 1) //Insta-button
1347 {
1348 GUI_EVENT(d, geCLICK);
1349 break;
1350 }
1351 /* or just toggle */
1352 d->flags ^= D_SELECTED;
1353 GUI_EVENT(d, geCLICK);
1354 object_message(d, MSG_DRAW, 0);
1355 break;
1356
1357 case MSG_CLICK:
1358 {
1359 if(disabled) break;
1360 if(d->d2 == 1) //Insta-button
1361 {
1362 if(mouse_in_rect(d->x, d->y, d->w, d->h))
1363 {
1364 GUI_EVENT(d, geCLICK);
1365 if(d->flags & D_EXIT)
1366 return D_CLOSE;
1367 }
1368 }
1369 else
1370 {
1371 last_draw = 0;
1372
1373 /* track the mouse until it is released */
1374 while(gui_mouse_b())
1375 {
1376 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1377
1378 /* redraw? */
1379 bool should_redraw = false;
1380 if(last_draw != down)
1381 {
1382 if(down != selected)
1383 d->flags |= D_SELECTED;
1384 else
1385 d->flags &= ~D_SELECTED;
1386
1387 object_message(d, MSG_DRAW, 0);
1388 last_draw = down;
1389 should_redraw = true;
1390 }
1391
1392 /* let other objects continue to animate */
1393 int r = broadcast_dialog_message(MSG_IDLE, 0);
1394 if (r & D_REDRAWME) should_redraw = true;
1395
1396 if (should_redraw)
1397 {
1398 update_hw_screen();
1399 }
1400 }
1401
1402 /* redraw in normal state */
1403 if(down)
1404 {
1405 GUI_EVENT(d, geCLICK);
1406 if(d->flags&D_EXIT)
1407 {
1408 d->flags &= ~D_SELECTED;
1409 object_message(d, MSG_DRAW, 0);
1410 }
1411 }
1412
1413 /* should we close the dialog? */
1414 if(down && (d->flags & D_EXIT))
1415 return D_CLOSE;
1416 }
1417 }
1418 break;
1419 }
1420 return D_O_K;
1421 }
1422 int32_t jwin_iconbutton_proc(int32_t msg, DIALOG *d, int32_t)
1423 {
1424 int32_t down=0;
1425 int32_t selected=(d->flags&D_SELECTED)?1:0;
1426 int32_t last_draw;
1427
1428 switch(msg)
1429 {
1430 case MSG_DRAW:
1431 {
1432 jwin_draw_icon_button(screen, d->x, d->y, d->w, d->h, d->d1, d->flags, true);
1433 }
1434 break;
1435
1436 case MSG_WANTFOCUS:
1437 return D_WANTFOCUS;
1438
1439 case MSG_KEY:
1440 /* close dialog? */
1441 if(d->flags & D_EXIT)
1442 {
1443 return D_CLOSE;
1444 }
1445 if(d->d2 == 1) //Insta-button
1446 {
1447 GUI_EVENT(d, geCLICK);
1448 break;
1449 }
1450 /* or just toggle */
1451 d->flags ^= D_SELECTED;
1452 GUI_EVENT(d, geCLICK);
1453 object_message(d, MSG_DRAW, 0);
1454 break;
1455
1456 case MSG_CLICK:
1457 {
1458 if(d->d2 == 1) //Insta-button
1459 {
1460 if(mouse_in_rect(d->x, d->y, d->w, d->h))
1461 {
1462 GUI_EVENT(d, geCLICK);
1463 if(d->flags & D_EXIT)
1464 return D_CLOSE;
1465 }
1466 }
1467 else
1468 {
1469 last_draw = 0;
1470
1471 /* track the mouse until it is released */
1472 while(gui_mouse_b())
1473 {
1474 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1475
1476 /* redraw? */
1477 bool should_redraw = false;
1478 if(last_draw != down)
1479 {
1480 if(down != selected)
1481 d->flags |= D_SELECTED;
1482 else
1483 d->flags &= ~D_SELECTED;
1484
1485 object_message(d, MSG_DRAW, 0);
1486 last_draw = down;
1487 should_redraw = true;
1488 }
1489
1490 /* let other objects continue to animate */
1491 int r = broadcast_dialog_message(MSG_IDLE, 0);
1492 if (r & D_REDRAWME) should_redraw = true;
1493
1494 if (should_redraw)
1495 {
1496 update_hw_screen();
1497 }
1498 }
1499
1500 /* redraw in normal state */
1501 if(down)
1502 {
1503 GUI_EVENT(d, geCLICK);
1504 if(d->flags&D_EXIT)
1505 {
1506 d->flags &= ~D_SELECTED;
1507 object_message(d, MSG_DRAW, 0);
1508 }
1509 }
1510
1511 /* should we close the dialog? */
1512 if(down && (d->flags & D_EXIT))
1513 return D_CLOSE;
1514 }
1515 }
1516 break;
1517 }
1518 return D_O_K;
1519 }
1520 int32_t jwin_infobtn_proc(int32_t msg, DIALOG *d, int32_t)
1521 {
1522 int32_t down=0;
1523 int32_t selected=(d->flags&D_SELECTED)?1:0;
1524 int32_t last_draw;
1525 std::string* str = (std::string*)d->dp;
1526 bool dis = (d->flags & D_DISABLED) || !str || !((*str)[0]) || str->find_first_not_of(" \t")==std::string::npos;
1527 int flags = d->flags | (dis?D_DISABLED:0);
1528 bool show = false;
1529 switch(msg)
1530 {
1531 case MSG_DRAW:
1532 {
1533 FONT *oldfont = font;
1534
1535 if(d->dp2)
1536 font = (FONT*)d->dp2;
1537
1538 jwin_draw_text_button(screen, d->x, d->y, d->w, d->h, "?", flags, true);
1539 font = oldfont;
1540 }
1541 break;
1542
1543 case MSG_WANTFOCUS:
1544 if(dis) break;
1545 return D_WANTFOCUS;
1546
1547 case MSG_KEY:
1548 if(dis) break;
1549 show = true;
1550 break;
1551
1552 case MSG_CLICK:
1553 {
1554 if(dis) break;
1555 if(d->d2 == 1) //Insta-button
1556 {
1557 if(mouse_in_rect(d->x, d->y, d->w, d->h))
1558 {
1559 show = true;
1560 break;
1561 }
1562 }
1563 else
1564 {
1565 last_draw = 0;
1566
1567 /* track the mouse until it is released */
1568 while(gui_mouse_b())
1569 {
1570 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1571
1572 /* redraw? */
1573 bool should_redraw = false;
1574 if(last_draw != down)
1575 {
1576 if(down != selected)
1577 d->flags |= D_SELECTED;
1578 else
1579 d->flags &= ~D_SELECTED;
1580
1581 object_message(d, MSG_DRAW, 0);
1582 last_draw = down;
1583 should_redraw = true;
1584 }
1585
1586 /* let other objects continue to animate */
1587 int r = broadcast_dialog_message(MSG_IDLE, 0);
1588 if (r & D_REDRAWME) should_redraw = true;
1589
1590 if (should_redraw)
1591 {
1592 update_hw_screen();
1593 }
1594 }
1595
1596 /* redraw in normal state */
1597 if(down)
1598 show = true;
1599 }
1600 }
1601 break;
1602 }
1603 if(show)
1604 {
1605 d->flags &= ~D_SELECTED;
1606 object_message(d, MSG_DRAW, 0);
1607 InfoDialog("Info",*str).show();
1608 GUI_EVENT(d, geCLICK);
1609 }
1610 return D_O_K;
1611 }
1612
1613 /* jwin_func_button_proc:
1614 * A button that runs a void() function when clicked.
1615 * dp: Button text
1616 * dp2: Function to run
1617 */
1618 int32_t jwin_func_button_proc(int32_t msg, DIALOG *d, int32_t c)
1619 {
1620 int32_t down=0;
1621 int32_t selected=(d->flags&D_SELECTED)?1:0;
1622 int32_t last_draw;
1623
1624 if(msg==MSG_CLICK || msg==MSG_KEY)
1625 {
1626 last_draw = 0;
1627
1628 /* track the mouse until it is released */
1629 while(gui_mouse_b())
1630 {
1631 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1632
1633 /* redraw? */
1634 bool should_redraw = false;
1635 if(last_draw != down)
1636 {
1637 if(down != selected)
1638 d->flags |= D_SELECTED;
1639 else
1640 d->flags &= ~D_SELECTED;
1641
1642 object_message(d, MSG_DRAW, 0);
1643 last_draw = down;
1644 should_redraw = true;
1645 }
1646
1647 /* let other objects continue to animate */
1648 int r = broadcast_dialog_message(MSG_IDLE, 0);
1649 if (r & D_REDRAWME) should_redraw = true;
1650
1651 if (should_redraw)
1652 {
1653 update_hw_screen();
1654 }
1655 }
1656
1657 /* redraw in normal state */
1658 if(down)
1659 {
1660 if(d->flags&D_EXIT)
1661 {
1662 d->flags &= ~D_SELECTED;
1663 object_message(d, MSG_DRAW, 0);
1664 }
1665 }
1666
1667 /* pop up and call the function */
1668 if(down)
1669 {
1670 d->flags &= ~D_SELECTED;
1671 object_message(d, MSG_DRAW, 0);
1672 typedef void (*funcType)(void);
1673 funcType func=reinterpret_cast<funcType>(d->dp3);
1674 func();
1675 }
1676
1677 return D_O_K;
1678 }
1679
1680 return jwin_button_proc(msg, d, c);
1681 }
1682
1683 /*(int32_t x = atoi(d->dp);
1684 if ( x > 256 )
1685 d->dp = (char*)"255";
1686 elseif (x < 0 ) d->dp = (char*)"0";
1687 */
1688
1689 #ifdef ALLEGRO_MACOSX
1690 static int WORD_FLAG = KB_ALT_FLAG;
1691 static int LINE_FLAG = KB_COMMAND_FLAG;
1692 #else
1693 static int WORD_FLAG = KB_CTRL_FLAG;
1694 static int LINE_FLAG = KB_ALT_FLAG;
1695 #endif
1696
1697 static int classify_char(char c)
1698 {
1699 if (c == ' ' || c == '\t' || c == '\r')
1700 return 0;
1701 if (c == '/' || c == '\\')
1702 return 1;
1703 return 2;
1704 }
1705
1706 static void delete_word(char* s, int* cursor)
1707 {
1708 int start = *cursor;
1709 if (start == 0) return;
1710
1711 int i = start - 1;
1712 int first_ch_class = classify_char(s[i]);
1713 while (i >= 0 && s[i])
1714 {
1715 if (classify_char(s[i]) != first_ch_class)
1716 break;
1717 i--;
1718 }
1719
1720 i++;
1721 *cursor = i;
1722
1723 int j = start;
1724 while (s[j])
1725 s[i++] = s[j++];
1726 s[i] = 0;
1727 }
1728
1729 static void delete_line(char* s, int* cursor)
1730 {
1731 int start = *cursor;
1732 if (start == 0) return;
1733
1734 int i = start - 1;
1735 while (i >= 0 && s[i])
1736 {
1737 bool is_newline = s[i] == '\n';
1738 if (is_newline) break;
1739 i--;
1740 }
1741
1742 i++;
1743 *cursor = i;
1744
1745 int j = start;
1746 while (s[j])
1747 s[i++] = s[j++];
1748 s[i] = 0;
1749 }
1750
1751 int32_t jwin_vedit_proc(int32_t msg, DIALOG *d, int32_t c)
1752 {
1753 if(d->flags & D_HIDDEN)
1754 {
1755 switch(msg)
1756 {
1757 case MSG_CHAR: case MSG_UCHAR: case MSG_XCHAR: case MSG_DRAW: case MSG_CLICK: case MSG_DCLICK: case MSG_KEY: case MSG_WANTFOCUS:
1758 return D_O_K;
1759 }
1760 }
1761 if(d->h < 2+((text_height(d->dp2 ? (FONT*)d->dp2 : font)+2)*2))
1762 return jwin_edit_proc(msg, d, c);
1763 static char nullbuf[2];
1764 sprintf(nullbuf, " ");
1765 int32_t f, l, p, w, x, y, fg, bg;
1766 int32_t lastSpace = -1;
1767 char *s;
1768 char buf[2] = {0,0};
1769
1770 if(d->dp==NULL)
1771 {
1772 d->dp=(void *)nullbuf;
1773 }
1774
1775 s = (char*)d->dp;
1776 l = (int32_t)strlen(s);
1777
1778 int32_t cursor_start = d->d2 & 0x0000FFFF;
1779 int32_t cursor_end = int32_t((d->d2 & 0xFFFF0000) >> 16);
1780 // This was previously doing bitshifts on -1. There wasn't enough space so I cannibalized 0xFFFF instead. -Moosh
1781 if (cursor_start == 0xFFFF)
1782 cursor_start = -1;
1783 if (cursor_end == 0xFFFF)
1784 cursor_end = -1;
1785
1786 if(cursor_start > l)
1787 cursor_start = l;
1788 if(cursor_end > l)
1789 cursor_end = l;
1790 auto low_cursor = cursor_start<0 ? cursor_end : (cursor_end<0 ? cursor_start : (zc_min(cursor_start, cursor_end)));
1791 auto high_cursor = zc_max(cursor_start,cursor_end);
1792 bool range_selected = cursor_end > -1;
1793
1794 FONT *oldfont = font;
1795 if(d->dp2)
1796 font = (FONT*)d->dp2;
1797
1798 auto* char_length = font->vtable->char_length;
1799 std::vector<size_t> lines;
1800 x = 0;
1801
1802 y = d->y + 2;
1803 size_t ind = 0;
1804 int32_t yinc = text_height(font)+2;
1805 int32_t maxy = y;
1806 size_t maxlines = 1;
1807 while(maxy+yinc < d->y+d->h-3)
1808 {
1809 maxy += yinc;
1810 ++maxlines;
1811 }
1812 size_t half_width = (maxlines-1)/2;
1813 size_t line_scroll = 0;
1814 size_t focused_line = size_t(-1);
1815 size_t focused_line2 = size_t(-1);
1816 switch(msg)
1817 {
1818 //Only these messages need these calculations, so save processing.
1819 case MSG_DRAW:
1820 case MSG_CLICK:
1821 case MSG_CHAR:
1822 {
1823 for(auto q = 0; q <= l; ++q)
1824 {
1825 char c = s[q] ? s[q] : ' ';
1826 x += char_length(font, c);
1827 if(x > d->w - 6)
1828 {
1829 // Line's too long, break
1830 if(lastSpace >= 0)
1831 {
1832 q = lastSpace+1;
1833 lines.push_back(q);
1834 lastSpace = -1;
1835 }
1836 else
1837 {
1838 lines.push_back(q);
1839 }
1840 x = 0;
1841 --q; //counteract increment
1842 }
1843 else if(c == ' ')
1844 lastSpace = q;
1845 }
1846 if(lines.empty() || lines.back() != l+1)
1847 lines.push_back(l+1);
1848 for(size_t line = 0; line < lines.size(); ++line)
1849 {
1850 if(size_t(range_selected ? cursor_end : cursor_start) < lines[line]) //should ALWAYS execute once
1851 {
1852 focused_line = line;
1853 break;
1854 }
1855 }
1856 if(!range_selected)
1857 {
1858 focused_line2 = -1;
1859 }
1860 else for(size_t line = 0; line < lines.size(); ++line)
1861 {
1862 if(size_t(cursor_start) < lines[line]) //should ALWAYS execute once
1863 {
1864 focused_line2 = line;
1865 break;
1866 }
1867 }
1868 if (focused_line >= lines.size())
1869 focused_line = lines.size() - 1;
1870 if (focused_line2 >= lines.size())
1871 focused_line2 = lines.size() - 1;
1872 if(maxlines >= lines.size() || focused_line <= half_width)
1873 line_scroll = 0;
1874 else if(lines.size()-maxlines+half_width < focused_line)
1875 line_scroll = lines.size()-maxlines+half_width-1;
1876 else
1877 line_scroll = focused_line - half_width;
1878 }
1879 }
1880 font = oldfont; //in case of early return, need to reset here
1881 static bool dclick = false;
1882 switch(msg)
1883 {
1884 case MSG_START:
1885 dclick = false;
1886 cursor_start = (int32_t)strlen((char*)d->dp);
1887 cursor_end = -1;
1888 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
1889 break;
1890
1891 case MSG_DRAW:
1892 {
1893 if(d->dp2)
1894 font = (FONT*)d->dp2;
1895 if(d->flags & D_DISABLED)
1896 {
1897 fg = scheme[jcDISABLED_FG];
1898 bg = scheme[jcDISABLED_BG];
1899 }
1900 else if(d->flags & D_READONLY)
1901 {
1902 fg = scheme[jcALT_TEXTFG];
1903 bg = scheme[jcALT_TEXTBG];
1904 }
1905 else
1906 {
1907 fg = scheme[jcTEXTFG];
1908 bg = scheme[jcTEXTBG];
1909 }
1910
1911 //Fill the BG
1912 rectfill(screen, d->x+2, d->y+2, d->x+d->w-3, d->y+d->h-3, bg);
1913
1914 //Now the text
1915 size_t m = zc_min(line_scroll + maxlines, lines.size());
1916 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DEEP);
1917 for(size_t line = line_scroll; line < m; ++line, y+=yinc)
1918 {
1919 x = 3;
1920 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
1921 {
1922 char c = s[ind] ? s[ind] : ' ';
1923 w = char_length(font, c);
1924 bool focused = range_selected
1925 ? (ind >= low_cursor && ind <= high_cursor)
1926 : (ind == cursor_start);
1927 f = (focused && (d->flags & D_GOTFOCUS));
1928 buf[0] = c;
1929 textout_ex(screen, font, buf, d->x+x, y, f ? bg : fg,f ? fg : bg);
1930 x += w;
1931 }
1932 }
1933
1934 font = oldfont;
1935 break;
1936 }
1937
1938 case MSG_DCLICK:
1939 if ((gui_mouse_b() & 2) != 0)
1940 break;
1941 if (d->flags & (D_DISABLED | D_READONLY))
1942 break;
1943 dclick = true;
1944 break;
1945 case MSG_CLICK:
1946 {
1947 int oldcursor = d->d2;
1948
1949 if(d->flags & (D_DISABLED|D_READONLY))
1950 break;
1951 if(d->dp2)
1952 font = (FONT*)d->dp2;
1953
1954 bool found = false;
1955 for(size_t line = line_scroll; line < lines.size() && line < (line_scroll + maxlines); ++line, y+=yinc)
1956 {
1957 if(gui_mouse_y() >= y+yinc)
1958 continue;
1959 x = d->x+3;
1960 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
1961 {
1962 x += char_length(font, s[ind]);
1963 if(x >= gui_mouse_x())
1964 {
1965 if(key_shifts&KB_SHIFT_FLAG)
1966 cursor_end = ind;
1967 else
1968 {
1969 cursor_start = ind;
1970 cursor_end = -1;
1971 if (dclick)
1972 cursor_end = cursor_start;
1973 }
1974 found = true;
1975 break;
1976 }
1977 }
1978 break;
1979 }
1980 if(!found)
1981 {
1982 if(key_shifts&KB_SHIFT_FLAG)
1983 cursor_end = l;
1984 else
1985 {
1986 cursor_start = l;
1987 cursor_end = -1;
1988 if (dclick)
1989 cursor_end = cursor_start;
1990 }
1991 }
1992
1993 if (dclick)
1994 {
1995 while (cursor_start > 0 && cursor_start < l)
1996 {
1997 if (s[cursor_start] == ' ')
1998 {
1999 if (cursor_start <= cursor_end)
2000 ++cursor_start;
2001 else
2002 --cursor_start;
2003 break;
2004 }
2005 // Select the entire SCC text (as long as user double clicks on the name part).
2006 if (s[cursor_start] == '\\' && (cursor_start > 0 && !isdigit(s[cursor_start - 1])))
2007 break;
2008 if (cursor_start <= cursor_end)
2009 --cursor_start;
2010 else
2011 ++cursor_start;
2012 }
2013 while (cursor_end > 0 && cursor_end < l)
2014 {
2015 if (s[cursor_end] == ' ')
2016 {
2017 if (cursor_end >= cursor_start)
2018 --cursor_end;
2019 else
2020 ++cursor_end;
2021 break;
2022 }
2023 // Select the entire SCC text (as long as user double clicks on the name part).
2024 if (s[cursor_end] == '\\' && (cursor_end == l - 1 || s[cursor_end + 1] == ' '))
2025 break;
2026 if (cursor_end >= cursor_start)
2027 ++cursor_end;
2028 else
2029 --cursor_end;
2030 }
2031 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2032 d->flags |= D_DIRTY;
2033 }
2034 else
2035 {
2036 if (cursor_end == cursor_start) cursor_end = -1;
2037 else d->flags |= D_DIRTY;
2038 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2039 }
2040
2041 object_message(d, MSG_DRAW, 0);
2042 font = oldfont;
2043 dclick = false;
2044 if (oldcursor != d->d2)
2045 GUI_EVENT(d, geCHANGE_CURSOR);
2046 break;
2047 }
2048
2049 case MSG_WANTFOCUS:
2050 case MSG_LOSTFOCUS:
2051 case MSG_KEY:
2052 if(d->flags & (D_DISABLED|D_READONLY))
2053 break;
2054 return D_WANTFOCUS;
2055
2056 case MSG_CHAR:
2057 {
2058 if(d->flags & (D_DISABLED|D_READONLY))
2059 break;
2060 bool shifted = key_shifts & KB_SHIFT_FLAG;
2061 bool ctrl = key_shifts & KB_CTRL_CMD_FLAG;
2062 bool word_modifier = key_shifts & WORD_FLAG;
2063 bool line_modifier = key_shifts & LINE_FLAG;
2064 bool change_cursor = true;
2065 int32_t scursor = cursor_start, ecursor = cursor_end;
2066 char upper_c = c>>8;
2067 char lower_c = c&255;
2068
2069 if(shifted)
2070 {
2071 if(ecursor < 0)
2072 {
2073 ecursor = scursor;
2074 focused_line2 = focused_line;
2075 }
2076 }
2077 if(upper_c == KEY_LEFT)
2078 {
2079 if(shifted)
2080 {
2081 if(ecursor>0)
2082 --ecursor;
2083 }
2084 else
2085 {
2086 ecursor = -1;
2087 if(scursor > 0)
2088 --scursor;
2089 }
2090 }
2091 else if(upper_c == KEY_RIGHT)
2092 {
2093 if(shifted)
2094 {
2095 if(ecursor < l)
2096 ++ecursor;
2097 }
2098 else
2099 {
2100 ecursor = -1;
2101 if(scursor < l)
2102 ++scursor;
2103 }
2104 }
2105 else if(upper_c == KEY_UP || upper_c == KEY_DOWN)
2106 {
2107 if(shifted)
2108 {
2109 size_t line = focused_line2 + (upper_c == KEY_UP ? -1 : 1);
2110 if(!focused_line2 && upper_c == KEY_UP)
2111 ecursor = 0;
2112 else if(line >= lines.size())
2113 ecursor = l;
2114 else
2115 {
2116 if(d->dp2)
2117 font = (FONT*)d->dp2;
2118 x = d->x + 3;
2119 for(ind = focused_line2 ? lines[focused_line2-1] : 0; ind < lines[focused_line2]; ++ind)
2120 {
2121 w = char_length(font, s[ind]);
2122 if(ind < size_t(ecursor))
2123 x += w;
2124 else
2125 {
2126 x += w / 2;
2127 break;
2128 }
2129 }
2130
2131 int32_t tx = d->x+3;
2132 bool done = false;
2133 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
2134 {
2135 tx += char_length(font, s[ind] ? s[ind] : ' ');
2136 if(tx < x)
2137 continue;
2138 ecursor = ind;
2139 done = true;
2140 break;
2141 }
2142 font = oldfont;
2143 if(!done)
2144 {
2145 ecursor = (upper_c == KEY_UP) ? 0 : lines[line]-1;
2146 }
2147 }
2148 }
2149 else
2150 {
2151 ecursor = -1;
2152 if(range_selected)
2153 {
2154 focused_line = focused_line2;
2155 scursor = ecursor;
2156 }
2157 size_t line = focused_line + (upper_c == KEY_UP ? -1 : 1);
2158 if(!focused_line && upper_c == KEY_UP)
2159 scursor = 0;
2160 else if(line >= lines.size())
2161 scursor = l;
2162 else
2163 {
2164 if(d->dp2)
2165 font = (FONT*)d->dp2;
2166 x = d->x + 3;
2167 for(ind = focused_line ? lines[focused_line-1] : 0; ind < lines[focused_line]; ++ind)
2168 {
2169 w = char_length(font, s[ind]);
2170 if(ind < size_t(scursor))
2171 x += w;
2172 else
2173 {
2174 x += w / 2;
2175 break;
2176 }
2177 }
2178
2179 int32_t tx = d->x+3;
2180 bool done = false;
2181 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
2182 {
2183 tx += char_length(font, s[ind] ? s[ind] : ' ');
2184 if(tx < x)
2185 continue;
2186 scursor = ind;
2187 done = true;
2188 break;
2189 }
2190 font = oldfont;
2191 if(!done)
2192 {
2193 scursor = (upper_c == KEY_UP) ? 0 : lines[line]-1;
2194 }
2195 }
2196 }
2197 }
2198 else if(upper_c == KEY_HOME)
2199 {
2200 if(shifted)
2201 ecursor = 0;
2202 else
2203 {
2204 ecursor = -1;
2205 scursor = 0;
2206 }
2207 }
2208 else if(upper_c == KEY_END)
2209 {
2210 if(shifted)
2211 ecursor = l;
2212 else
2213 {
2214 ecursor = -1;
2215 scursor = l;
2216 }
2217 }
2218 else if(upper_c == KEY_DEL)
2219 {
2220 if(ctrl)
2221 {
2222 s[0] = 0;
2223 scursor = 0;
2224 ecursor = -1;
2225 GUI_EVENT(d, geCHANGE_VALUE);
2226 }
2227 else if(range_selected)
2228 {
2229 ecursor = -1;
2230 scursor = low_cursor;
2231 size_t ind = low_cursor, ind2 = high_cursor+1;
2232 while(ind2 < l && s[ind2])
2233 s[ind++] = s[ind2++];
2234 while(s[ind])
2235 s[ind++] = 0;
2236 GUI_EVENT(d, geCHANGE_VALUE);
2237 }
2238 else if(scursor < l)
2239 {
2240 for(p=scursor; s[p]; p++)
2241 s[p] = s[p+1];
2242 GUI_EVENT(d, geCHANGE_VALUE);
2243 }
2244 }
2245 else if(upper_c == KEY_BACKSPACE)
2246 {
2247 if(line_modifier)
2248 {
2249 delete_line(s, &scursor);
2250 ecursor = -1;
2251 GUI_EVENT(d, geCHANGE_VALUE);
2252 }
2253 else if(word_modifier)
2254 {
2255 delete_word(s, &scursor);
2256 ecursor = -1;
2257 GUI_EVENT(d, geCHANGE_VALUE);
2258 }
2259 else if(range_selected)
2260 {
2261 ecursor = -1;
2262 scursor = low_cursor;
2263 size_t ind = low_cursor, ind2 = high_cursor+1;
2264 while(ind2 < l && s[ind2])
2265 s[ind++] = s[ind2++];
2266 while(s[ind])
2267 s[ind++] = 0;
2268 GUI_EVENT(d, geCHANGE_VALUE);
2269 }
2270 else if(scursor > 0)
2271 {
2272 --scursor;
2273 for(p=scursor; s[p]; p++)
2274 s[p] = s[p+1];
2275 GUI_EVENT(d, geCHANGE_VALUE);
2276 }
2277 }
2278 else if(upper_c == KEY_ENTER)
2279 {
2280 change_cursor = false;
2281 GUI_EVENT(d, geENTER);
2282 if(d->flags & D_EXIT)
2283 {
2284 object_message(d, MSG_DRAW, 0);
2285 return D_CLOSE;
2286 }
2287 else
2288 return D_O_K;
2289 }
2290 else if(upper_c == KEY_TAB)
2291 {
2292 change_cursor = false;
2293 return D_O_K;
2294 }
2295 else if(ctrl && upper_c == KEY_C)
2296 {
2297 change_cursor = false;
2298 std::ostringstream oss;
2299 if(range_selected)
2300 {
2301 for(size_t ind = low_cursor; ind <= high_cursor; ++ind)
2302 {
2303 if(s[ind])
2304 oss << s[ind];
2305 }
2306 }
2307 else
2308 {
2309 if(s[scursor])
2310 oss << s[scursor];
2311 }
2312 set_al_clipboard(oss.str());
2313 }
2314 else if (ctrl && upper_c == KEY_V && clipboard_has_text())
2315 {
2316 std::string cb;
2317 if(get_al_clipboard(cb))
2318 {
2319 int ind = low_cursor, ind2 = high_cursor + 1;
2320 if (range_selected)
2321 {
2322 //Delete selected text
2323 ecursor = -1;
2324 scursor = low_cursor;
2325 while (s[ind2] && ind2 < l)
2326 s[ind++] = s[ind2++];
2327 while (s[ind])
2328 s[ind++] = 0;
2329 l = (int32_t)strlen(s);
2330 }
2331 //Move the text out of the way of the pasting
2332 int paste_len = cb.size();
2333 int paste_start = scursor;
2334 int paste_end = paste_start+paste_len;
2335 ind = strlen(s);
2336 ind2 = ind+paste_len;
2337 while(ind2 > d->d1)
2338 {
2339 --ind;
2340 --ind2;
2341 }
2342 size_t new_l = ind2;
2343 while(ind >= paste_start)
2344 {
2345 if(s[ind] || (ind&&s[ind-1]))
2346 {
2347 s[ind2] = s[ind];
2348 }
2349 --ind2; --ind;
2350 }
2351 for(auto q = 0; q < paste_len && paste_start+q < new_l; ++q)
2352 {
2353 s[paste_start+q] = cb.at(q);
2354 }
2355 s[new_l] = 0;
2356 scursor = paste_start + paste_len;
2357 ecursor = -1;
2358 GUI_EVENT(d, geCHANGE_VALUE);
2359 }
2360 }
2361 else if (ctrl && upper_c == KEY_A)
2362 {
2363 cursor_start = 0;
2364 cursor_end = (int16_t)strlen((char*)d->dp) - 1;
2365 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2366 d->flags |= D_DIRTY;
2367 GUI_EVENT(d, geCHANGE_CURSOR);
2368 break;
2369 }
2370 else if(lower_c >= 32 && !ctrl)
2371 {
2372 if(range_selected)
2373 {
2374 //Delete selected text
2375 ecursor = -1;
2376 scursor = low_cursor;
2377 size_t ind = low_cursor, ind2 = high_cursor+1;
2378 while(ind2 < l && s[ind2])
2379 s[ind++] = s[ind2++];
2380 while(s[ind])
2381 s[ind++] = 0;
2382 l = (int32_t)strlen(s);
2383 //Type the character in its' place
2384 //(fallthrough)
2385 }
2386 if(l < d->d1)
2387 {
2388 ecursor = -1;
2389 s[l+1] = 0;
2390 size_t ind = l;
2391 while(ind >= scursor)
2392 {
2393 s[ind+1] = s[ind];
2394 if (!ind) break;
2395 --ind;
2396 }
2397
2398 s[scursor++] = lower_c;
2399
2400 GUI_EVENT(d, geCHANGE_VALUE);
2401 }
2402 }
2403 else
2404 return D_O_K;
2405
2406 if(change_cursor)
2407 {
2408 if (cursor_start != scursor)
2409 d->flags |= D_DIRTY;
2410
2411 cursor_end = ecursor; cursor_start = scursor;
2412 if (cursor_end == cursor_start) cursor_end = -1;
2413 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2414
2415 GUI_EVENT(d, geCHANGE_CURSOR);
2416 }
2417
2418 /* if we changed something, better redraw... */
2419 object_message(d, MSG_DRAW, 0);
2420 return D_USED_CHAR;
2421 }
2422 }
2423
2424 return D_O_K;
2425 }
2426
2427 /* jwin_edit_proc:
2428 * An editable text object (the dp field points to the string). When it
2429 * has the input focus (obtained by clicking on it with the mouse), text
2430 * can be typed into this object. The d1 field specifies the maximum
2431 * number of characters that it will accept, and d2 is the text cursor
2432 * position within the string.
2433 */
2434 int32_t jwin_edit_proc(int32_t msg, DIALOG *d, int32_t c)
2435 {
2436 if(d->flags & D_HIDDEN)
2437 {
2438 switch(msg)
2439 {
2440 case MSG_CHAR: case MSG_UCHAR: case MSG_XCHAR: case MSG_DRAW: case MSG_CLICK: case MSG_DCLICK: case MSG_KEY: case MSG_WANTFOCUS:
2441 return D_O_K;
2442 }
2443 }
2444 if(d->h >= 2+((text_height(d->dp2 ? (FONT*)d->dp2 : font)+2)*2))
2445 return jwin_vedit_proc(msg, d, c);
2446 int32_t f, l, p, w, x, y, fg, bg, fg2 = -1, bg2 = -1, fg3, bg3;
2447 int32_t b;
2448 int32_t scroll;
2449 char *s;
2450 char buf[2];
2451 static char nullbuf[2];
2452 sprintf(nullbuf, " ");
2453
2454 if(d->dp==NULL)
2455 {
2456 d->dp=(void *)nullbuf;
2457 }
2458
2459 s = (char*)d->dp;
2460 l = (int32_t)strlen(s);
2461
2462 int32_t cursor_start = d->d2 & 0x0000FFFF;
2463 int32_t cursor_end = int32_t((d->d2 & 0xFFFF0000) >> 16);
2464 // This was previously doing bitshifts on -1. There wasn't enough space so I cannibalized 0xFFFF instead. -Moosh
2465 if (cursor_start == 0xFFFF)
2466 cursor_start = -1;
2467 if (cursor_end == 0xFFFF)
2468 cursor_end = -1;
2469
2470 if(cursor_start > l)
2471 cursor_start = l;
2472 if(cursor_end > l)
2473 cursor_end = l;
2474 auto low_cursor = cursor_start<0 ? cursor_end : (cursor_end<0 ? cursor_start : (zc_min(cursor_start, cursor_end)));
2475 auto high_cursor = zc_max(cursor_start,cursor_end);
2476
2477 /* calculate maximal number of displayable characters */
2478 b = x = 0;
2479
2480 if(cursor_start == l)
2481 {
2482 buf[0] = ' ';
2483 buf[1] = 0;
2484
2485 if(d->dp2)
2486 x = text_length((FONT*)d->dp2, buf);
2487 else
2488 x = text_length(font, buf);
2489 }
2490
2491 buf[1] = 0;
2492
2493 for(p=cursor_start; p>=0; p--)
2494 {
2495 buf[0] = s[p];
2496 b++;
2497
2498 if(d->dp2)
2499 x += text_length((FONT*)d->dp2, buf);
2500 else
2501 x += text_length(font, buf);
2502
2503 if(x > d->w-6)
2504 break;
2505 }
2506
2507 if(x <= d->w-6)
2508 {
2509 b = l;
2510 scroll = FALSE;
2511 }
2512 else
2513 {
2514 b--;
2515 scroll = TRUE;
2516 }
2517
2518 FONT *oldfont = font;
2519 static bool dclick = false;
2520 switch(msg)
2521 {
2522 case MSG_START:
2523 dclick = false;
2524 cursor_start = (int32_t)strlen((char*)d->dp);
2525 cursor_end = -1;
2526 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2527 break;
2528
2529 case MSG_DRAW:
2530 {
2531 if(d->dp2)
2532 {
2533 font = (FONT*)d->dp2;
2534 }
2535 if(d->flags & D_DISABLED)
2536 {
2537 fg2 = scheme[jcLIGHT];
2538 bg2 = scheme[jcDISABLED_BG];
2539 fg = scheme[jcDISABLED_FG];
2540 bg = -1;
2541 fg3 = fg;
2542 bg3 = bg2;
2543 }
2544 else if(d->flags & D_READONLY)
2545 {
2546 fg = scheme[jcALT_TEXTFG];
2547 bg = scheme[jcALT_TEXTBG];
2548 fg3 = fg;
2549 bg3 = bg;
2550 }
2551 else
2552 {
2553 fg = scheme[jcTEXTFG];
2554 bg = scheme[jcTEXTBG];
2555 fg3 = fg;
2556 bg3 = bg;
2557 }
2558
2559 x = 3;
2560 y = (d->h - text_height(font)) / 2 + d->y;
2561
2562 /* first fill in the edges */
2563
2564 rectfill(screen, d->x+2, d->y+2, d->x+d->w-3, d->y+d->h-3, bg3);
2565
2566 vline(screen, d->x+2, d->y+2, d->y+d->h-3, bg3);
2567
2568 /* now the text */
2569
2570 if(scroll)
2571 {
2572 p = cursor_start-b+1;
2573 b = cursor_start;
2574 }
2575 else
2576 p = 0;
2577 for(; p<=b; p++)
2578 {
2579 buf[0] = s[p] ? s[p] : ' ';
2580 w = text_length(font, buf);
2581
2582 if(x+w > d->w)
2583 break;
2584 bool focused = (cursor_end>-1)
2585 ? (p >= low_cursor && p <= high_cursor)
2586 : (p == cursor_start);
2587 f = fg2 < 0 && (focused && (d->flags & D_GOTFOCUS));
2588 if(fg2 > -1)
2589 {
2590 textout_ex(screen, font, buf, d->x+x+1, y+1, fg2, bg2);
2591 }
2592 textout_ex(screen, font, buf, d->x+x, y, f ? bg : fg,f ? fg : bg);
2593 x += w;
2594 }
2595
2596 if(x < d->w-2)
2597 rectfill(screen, d->x+x, y, d->x+d->w-3, y+text_height(font)-1, bg3);
2598
2599 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DEEP);
2600 font = oldfont;
2601 break;
2602 }
2603
2604 case MSG_DCLICK:
2605 if ((gui_mouse_b() & 2) != 0)
2606 break;
2607 if (d->flags & (D_DISABLED | D_READONLY))
2608 break;
2609 dclick = true;
2610 break;
2611 case MSG_CLICK:
2612 {
2613 if(d->flags & (D_DISABLED|D_READONLY))
2614 break;
2615 x = d->x+3;
2616
2617 if(scroll)
2618 {
2619 p = cursor_start-b+1;
2620 b = cursor_start;
2621 }
2622 else
2623 p = 0;
2624
2625 for(; p<b; p++)
2626 {
2627 buf[0] = s[p];
2628 x += text_length((d->dp2) ? (FONT*)d->dp2 : font, buf);
2629
2630 if(x > gui_mouse_x())
2631 break;
2632 }
2633
2634 if(key_shifts&KB_SHIFT_FLAG)
2635 cursor_end = MID(0, p, l);
2636 else
2637 {
2638 cursor_end = -1;
2639 cursor_start = MID(0, p, l);
2640 if (dclick)
2641 cursor_end = cursor_start;
2642 }
2643
2644 if (dclick)
2645 {
2646 while (cursor_start > 0 && cursor_start < l)
2647 {
2648 if (s[cursor_start] == ' ')
2649 {
2650 if (cursor_start <= cursor_end)
2651 ++cursor_start;
2652 else
2653 --cursor_start;
2654 break;
2655 }
2656 if (cursor_start <= cursor_end)
2657 --cursor_start;
2658 else
2659 ++cursor_start;
2660 }
2661 while (cursor_end > 0 && cursor_end < l)
2662 {
2663 if (s[cursor_end] == ' ')
2664 {
2665 if (cursor_end >= cursor_start)
2666 --cursor_end;
2667 else
2668 ++cursor_end;
2669 break;
2670 }
2671 if (cursor_end >= cursor_start)
2672 ++cursor_end;
2673 else
2674 --cursor_end;
2675 }
2676 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2677 d->flags |= D_DIRTY;
2678 }
2679 else
2680 {
2681 if (cursor_end == cursor_start) cursor_end = -1;
2682 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2683 }
2684 d->flags |= D_DIRTY;
2685 dclick = false;
2686 break;
2687 }
2688
2689 case MSG_WANTFOCUS:
2690 case MSG_LOSTFOCUS:
2691 case MSG_KEY:
2692 if(d->flags & (D_DISABLED|D_READONLY))
2693 break;
2694 return D_WANTFOCUS;
2695
2696 case MSG_CHAR:
2697 {
2698 if(d->flags & (D_DISABLED|D_READONLY))
2699 break;
2700 bool shifted = key_shifts & KB_SHIFT_FLAG;
2701 bool ctrl = key_shifts & KB_CTRL_CMD_FLAG;
2702 bool word_modifier = key_shifts & WORD_FLAG;
2703 bool line_modifier = key_shifts & LINE_FLAG;
2704 bool change_cursor = true;
2705 bool change_value = false;
2706 int scursor = cursor_start, ecursor = cursor_end;
2707 bool range_selected = cursor_end > -1;
2708 auto upper_c = c>>8;
2709 auto lower_c = c&0xFF;
2710
2711 if(shifted)
2712 {
2713 if(ecursor < 0)
2714 ecursor = scursor;
2715 }
2716 if(upper_c == KEY_LEFT)
2717 {
2718 if(shifted)
2719 {
2720 if(ecursor>0)
2721 --ecursor;
2722 }
2723 else
2724 {
2725 ecursor = -1;
2726 if(scursor > 0)
2727 --scursor;
2728 }
2729 }
2730 else if(upper_c == KEY_RIGHT)
2731 {
2732 if(shifted)
2733 {
2734 if(ecursor < l)
2735 ++ecursor;
2736 }
2737 else
2738 {
2739 ecursor = -1;
2740 if(scursor < l)
2741 ++scursor;
2742 }
2743 }
2744 else if(upper_c == KEY_HOME)
2745 {
2746 if(shifted)
2747 ecursor = 0;
2748 else
2749 {
2750 ecursor = -1;
2751 scursor = 0;
2752 }
2753 }
2754 else if(upper_c == KEY_END)
2755 {
2756 if(shifted)
2757 ecursor = l;
2758 else
2759 {
2760 ecursor = -1;
2761 scursor = l;
2762 }
2763 }
2764 else if(upper_c == KEY_DEL)
2765 {
2766 if(ctrl)
2767 {
2768 s[0] = 0;
2769 scursor = 0;
2770 ecursor = -1;
2771 GUI_EVENT(d, geCHANGE_VALUE);
2772 change_value = true;
2773 }
2774 else if(range_selected)
2775 {
2776 ecursor = -1;
2777 scursor = low_cursor;
2778 int ind = low_cursor, ind2 = high_cursor+1;
2779 ind2 = std::min(ind2, d->d1 - 1);
2780 while(s[ind2])
2781 s[ind++] = s[ind2++];
2782 while(s[ind])
2783 s[ind++] = 0;
2784 GUI_EVENT(d, geCHANGE_VALUE);
2785 change_value = true;
2786 }
2787 else if(scursor < l)
2788 {
2789 for(p=scursor; s[p]; p++)
2790 s[p] = s[p+1];
2791 GUI_EVENT(d, geCHANGE_VALUE);
2792 change_value = true;
2793 }
2794 }
2795 else if(upper_c == KEY_BACKSPACE)
2796 {
2797 if(line_modifier)
2798 {
2799 delete_line(s, &scursor);
2800 ecursor = -1;
2801 GUI_EVENT(d, geCHANGE_VALUE);
2802 change_value = true;
2803 }
2804 else if(word_modifier)
2805 {
2806 delete_word(s, &scursor);
2807 ecursor = -1;
2808 GUI_EVENT(d, geCHANGE_VALUE);
2809 change_value = true;
2810 }
2811 else if(range_selected)
2812 {
2813 ecursor = -1;
2814 scursor = low_cursor;
2815 size_t ind = low_cursor, ind2 = high_cursor+1;
2816 while(ind2 < l && s[ind2])
2817 s[ind++] = s[ind2++];
2818 while(s[ind])
2819 s[ind++] = 0;
2820 GUI_EVENT(d, geCHANGE_VALUE);
2821 change_value = true;
2822 }
2823 else if(scursor > 0)
2824 {
2825 --scursor;
2826 for(p=scursor; s[p]; p++)
2827 s[p] = s[p+1];
2828 GUI_EVENT(d, geCHANGE_VALUE);
2829 change_value = true;
2830 }
2831 }
2832 else if(upper_c == KEY_ENTER)
2833 {
2834 change_cursor = false;
2835 GUI_EVENT(d, geENTER);
2836 if(d->flags & D_EXIT)
2837 {
2838 object_message(d, MSG_DRAW, 0);
2839 return D_CLOSE;
2840 }
2841 else
2842 return D_O_K;
2843 }
2844 else if(upper_c == KEY_TAB)
2845 {
2846 change_cursor = false;
2847 return D_O_K;
2848 }
2849 else if (ctrl && upper_c == KEY_C)
2850 {
2851 change_cursor = false;
2852 std::ostringstream oss;
2853 if(range_selected)
2854 {
2855 for(size_t ind = low_cursor; ind <= high_cursor; ++ind)
2856 {
2857 if(s[ind])
2858 oss << s[ind];
2859 }
2860 }
2861 else
2862 {
2863 if(s[scursor])
2864 oss << s[scursor];
2865 }
2866 set_al_clipboard(oss.str());
2867 }
2868 else if (ctrl && upper_c == KEY_V && clipboard_has_text())
2869 {
2870 std::string cb;
2871 if(get_al_clipboard(cb))
2872 {
2873 int ind = low_cursor, ind2 = high_cursor + 1;
2874 if (range_selected)
2875 {
2876 //Delete selected text
2877 ecursor = -1;
2878 scursor = low_cursor;
2879 while (s[ind2] && ind2 < l)
2880 s[ind++] = s[ind2++];
2881 while (s[ind])
2882 s[ind++] = 0;
2883 l = (int32_t)strlen(s);
2884 }
2885 //Move the text out of the way of the pasting
2886 int paste_len = cb.size();
2887 int paste_start = scursor;
2888 int paste_end = paste_start+paste_len;
2889 ind = strlen(s);
2890 ind2 = ind+paste_len;
2891 while(ind2 > d->d1)
2892 {
2893 --ind;
2894 --ind2;
2895 }
2896 size_t new_l = ind2;
2897 while(ind >= paste_start)
2898 {
2899 if(s[ind] || (ind&&s[ind-1]))
2900 {
2901 s[ind2] = s[ind];
2902 }
2903 --ind2; --ind;
2904 }
2905 for(auto q = 0; q < paste_len && paste_start+q < new_l; ++q)
2906 {
2907 s[paste_start+q] = cb.at(q);
2908 }
2909 s[new_l] = 0;
2910 scursor = paste_start + paste_len;
2911 ecursor = -1;
2912 GUI_EVENT(d, geCHANGE_VALUE);
2913 change_value = true;
2914 }
2915 }
2916 else if (ctrl && upper_c == KEY_A)
2917 {
2918 cursor_start = 0;
2919 cursor_end = (int16_t)strlen((char*)d->dp) - 1;
2920 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2921 d->flags |= D_DIRTY;
2922 break;
2923 }
2924 else if(lower_c >= 32 && !ctrl)
2925 {
2926 if(range_selected)
2927 {
2928 //Delete selected text
2929 ecursor = -1;
2930 scursor = low_cursor;
2931 int ind = low_cursor, ind2 = high_cursor+1;
2932 // ind2 = std::min(ind2, d->d1);
2933 while(s[ind2] && ind2 < l)
2934 s[ind++] = s[ind2++];
2935 while(s[ind])
2936 s[ind++] = 0;
2937 l = (int32_t)strlen(s);
2938 //Type the character in its' place
2939 //(fallthrough)
2940 }
2941 if(l < d->d1)
2942 {
2943 ecursor = -1;
2944 s[l+1] = 0;
2945 size_t ind = l;
2946 while(ind >= scursor)
2947 {
2948 s[ind+1] = s[ind];
2949 if (!ind) break;
2950 --ind;
2951 }
2952
2953 s[scursor++] = lower_c;
2954
2955 GUI_EVENT(d, geCHANGE_VALUE);
2956 change_value = true;
2957 }
2958 }
2959 else
2960 return D_O_K;
2961 if(change_cursor)
2962 {
2963 cursor_end = ecursor; cursor_start = scursor;
2964 if (cursor_end == cursor_start) cursor_end = -1;
2965 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2966 }
2967 /* if we changed something, better redraw... */
2968 // Note: this still redraws when not necessary.
2969 if (change_value || change_cursor)
2970 d->flags |= D_DIRTY;
2971 return D_USED_CHAR;
2972 }
2973 }
2974 return D_O_K;
2975 }
2976
2977 int32_t jwin_hexedit_proc_old(int32_t msg,DIALOG *d,int32_t c)
2978 {
2979 if(msg==MSG_CHAR)
2980 if(((isalpha(c&255) && !isxdigit(c&255))) || ispunct(c&255))
2981 return D_USED_CHAR;
2982
2983 return jwin_edit_proc(msg,d,isalpha(c&255)?c&0xDF:c);
2984 }
2985
2986 bool editproc_special_key(int32_t c)
2987 {
2988 switch(c>>8)
2989 {
2990 case KEY_LEFT: case KEY_RIGHT:
2991 case KEY_HOME: case KEY_END:
2992 case KEY_DEL: case KEY_BACKSPACE:
2993 case KEY_ENTER: case KEY_TAB:
2994 return true;
2995 }
2996 if(key_shifts & KB_CTRL_CMD_FLAG)
2997 switch(c&255)
2998 {
2999 case 'c': case 'C':
3000 return true;
3001 case 'v': case 'V':
3002 return clipboard_has_text();
3003 }
3004 return false;
3005 }
3006 bool editproc_combined_key(int32_t c)
3007 {
3008 if(key_shifts & KB_CTRL_CMD_FLAG)
3009 switch(c&255)
3010 {
3011 case 'c': case 'C':
3012 return true;
3013 case 'v': case 'V':
3014 return clipboard_has_text();
3015 }
3016 return false;
3017 }
3018 int32_t jwin_hexedit_proc(int32_t msg,DIALOG *d,int32_t c)
3019 {
3020 bool caps_paste = false;
3021 if(msg==MSG_CHAR)
3022 {
3023 if(key_shifts & KB_CTRL_CMD_FLAG)
3024 {
3025 if(clipboard_has_text() && ((c&255)=='v' || (c&255)=='V'))
3026 {
3027 std::string cb;
3028 if(get_al_clipboard(cb))
3029 {
3030 if(cb.find_first_not_of("-.0123456789ABCDEFabcdef") != std::string::npos)
3031 return D_USED_CHAR;
3032 if(cb.find_first_of("abcdef") != std::string::npos)
3033 caps_paste = true;
3034 }
3035 else return D_USED_CHAR;
3036 }
3037 }
3038 switch(c&255)
3039 {
3040 case '-': case '.':
3041 case '0': case '1': case '2': case '3': case '4':
3042 case '5': case '6': case '7': case '8': case '9':
3043 case 'A': case 'B': case 'C':
3044 case 'D': case 'E': case 'F':
3045 break;
3046 case 'a': case 'b': case 'c':
3047 case 'd': case 'e': case 'f':
3048 c = (c&~255)|toupper(c&255);
3049 break;
3050 default:
3051 if(!editproc_special_key(c))
3052 return D_O_K;
3053 else if(!editproc_combined_key(c))
3054 c&=~255;
3055 }
3056 }
3057
3058 auto ret = jwin_edit_proc(msg,d,c);
3059 if(caps_paste)
3060 {
3061 char* s = (char*)d->dp;
3062 caps_paste = false;
3063 for(int q = strlen(s)-1; q >= 0; --q)
3064 {
3065 switch(s[q])
3066 {
3067 case 'a': case 'b': case 'c':
3068 case 'd': case 'e': case 'f':
3069 s[q] = toupper(s[q]);
3070 caps_paste = true;
3071 break;
3072 }
3073 }
3074 if(caps_paste)
3075 {
3076 jwin_edit_proc(MSG_DRAW,d,0);
3077 }
3078 }
3079 return ret;
3080 }
3081 int32_t jwin_numedit_proc(int32_t msg,DIALOG *d,int32_t c)
3082 {
3083 if(msg==MSG_CHAR)
3084 {
3085 if(key_shifts & KB_CTRL_CMD_FLAG)
3086 {
3087 if(clipboard_has_text() && ((c&255)=='v' || (c&255)=='V'))
3088 {
3089 std::string cb;
3090 if(get_al_clipboard(cb))
3091 {
3092 if(cb.find_first_not_of("-.0123456789") != std::string::npos)
3093 return D_USED_CHAR;
3094 }
3095 else return D_USED_CHAR;
3096 }
3097 }
3098 switch(c&255)
3099 {
3100 case '-': case '.':
3101 case '0': case '1': case '2': case '3': case '4':
3102 case '5': case '6': case '7': case '8': case '9':
3103 break;
3104 default:
3105 if(!editproc_special_key(c))
3106 return D_O_K;
3107 else if(!editproc_combined_key(c))
3108 c&=~255;
3109 }
3110 }
3111
3112 return jwin_edit_proc(msg,d,c);
3113 }
3114
3115 int32_t jwin_numedit_byte_proc(int32_t msg,DIALOG *d,int32_t c)
3116 {
3117 if ( (atoi((char*)d->dp)) > 255 )
3118 {
3119 strcpy((char*)d->dp,"255\0");
3120 return jwin_numedit_proc(msg,d,c);
3121 }
3122 else if ( (atoi((char*)d->dp)) < 0 )
3123 {
3124 strcpy((char*)d->dp,"0\0");
3125 return jwin_numedit_proc(msg,d,c);
3126 }
3127
3128 return jwin_numedit_proc(msg,d,c);
3129 }
3130
3131 int32_t jwin_numedit_short_proc(int32_t msg,DIALOG *d,int32_t c)
3132 {
3133 if ( (atoi((char*)d->dp)) > 65535 )
3134 {
3135 strcpy((char*)d->dp,"65535\0");
3136 return jwin_numedit_proc(msg,d,c);
3137 }
3138 else if ( (atoi((char*)d->dp)) < 0 )
3139 {
3140 strcpy((char*)d->dp,"0\0");
3141 return jwin_numedit_proc(msg,d,c);
3142 }
3143
3144 return jwin_numedit_proc(msg,d,c);
3145 }
3146
3147 int32_t jwin_numedit_zscriptint_proc(int32_t msg,DIALOG *d,int32_t c)
3148 {
3149 if ( (atoi((char*)d->dp)) > 214748 )
3150 {
3151 strcpy((char*)d->dp,"214748\0");
3152 return jwin_numedit_proc(msg,d,c);
3153 }
3154 else if ( (atoi((char*)d->dp)) < -214748 )
3155 {
3156 strcpy((char*)d->dp,"-214748\0");
3157 return jwin_numedit_proc(msg,d,c);
3158 }
3159
3160 return jwin_numedit_proc(msg,d,c);
3161 }
3162
3163 int32_t jwin_numedit_sshort_proc(int32_t msg,DIALOG *d,int32_t c)
3164 {
3165 if ( (atoi((char*)d->dp)) > 32767 )
3166 {
3167 strcpy((char*)d->dp,"32767\0");
3168 return jwin_numedit_proc(msg,d,c);
3169 }
3170 else if ( (atoi((char*)d->dp)) < -32768 )
3171 {
3172 strcpy((char*)d->dp,"-32768\0");
3173 return jwin_numedit_proc(msg,d,c);
3174 }
3175
3176 return jwin_numedit_proc(msg,d,c);
3177 }
3178
3179 int32_t jwin_numedit_sbyte_proc(int32_t msg,DIALOG *d,int32_t c)
3180 {
3181 if ( (atoi((char*)d->dp)) > 127 )
3182 {
3183 strcpy((char*)d->dp,"127\0");
3184 return jwin_numedit_proc(msg,d,c);
3185 }
3186 else if ( (atoi((char*)d->dp)) < -128 )
3187 {
3188 strcpy((char*)d->dp,"-128\0");
3189 return jwin_numedit_proc(msg,d,c);
3190 }
3191
3192 return jwin_numedit_proc(msg,d,c);
3193 }
3194
3195 // Special numedit procs
3196
3197 void trim_trailing_0s(char* str, bool leaveDec = false)
3198 {
3199 bool foundDec = false;
3200 for(int32_t q = 0; str[q]; ++q)
3201 {
3202 if(str[q] == '.')
3203 {
3204 foundDec = true;
3205 break;
3206 }
3207 }
3208 if(!foundDec) return; //No decimal place, thus no trailing 0's.
3209 for(int32_t q = strlen(str)-1; q > 0; --q)
3210 {
3211 if(str[q] == '0' && (!leaveDec || str[q-1] != '.'))
3212 {
3213 str[q] = 0;
3214 }
3215 else if(str[q] == '.')
3216 {
3217 str[q] = 0;
3218 return;
3219 }
3220 else return;
3221 }
3222 }
3223 int32_t jwin_swapbtn_proc(int32_t msg, DIALOG* d, int32_t c)
3224 {
3225 static const char* swp[nswapMAX] = {"D", "H", "LD", "LH", "B"};
3226 d->dp = (void*)swp[d->d1&0xF];
3227 //d1 is (0xF0 = old val, 0x0F = new val)
3228 //d2 is max val
3229 if(d->d2 < 2 || d->d2 > nswapMAX) return D_O_K; //Not setup yet, or bad value
3230 DIALOG* relproc = (DIALOG*)d->dp3;
3231 GUI::TextField *tf_obj = nullptr;
3232 if(d->d2 > nswapBOOL) tf_obj = (GUI::TextField*)relproc->dp3;
3233 int32_t ret = jwin_button_proc(msg, d, c);
3234 if(d->flags & D_SELECTED) //On selection
3235 {
3236 d->d1 = ((d->d1&0x0F)<<4) | (((d->d1&0x0F)+1)%d->d2);
3237 d->dp = (void*)swp[d->d1&0xF];
3238 d->flags &= ~D_SELECTED;
3239 if(tf_obj) tf_obj->refresh_cb_swap();
3240 if(relproc)
3241 {
3242 object_message(relproc, MSG_DRAW, 0);
3243 }
3244 object_message(d, MSG_DRAW, 0);
3245 }
3246 return ret;
3247 }
3248 int32_t jwin_numedit_swap_byte_proc(int32_t msg, DIALOG *d, int32_t c)
3249 {
3250 DIALOG* swapbtn;
3251 if(d->flags&D_NEW_GUI)
3252 {
3253 swapbtn = d+1;
3254 }
3255 else swapbtn = (DIALOG*)d->dp3;
3256 if(!swapbtn) return D_O_K;
3257 if(msg==MSG_START) //Setup the swapbtn
3258 {
3259 d->bg = 0;
3260 swapbtn->d2 = 2; //Max states
3261 auto ty = swapbtn->d1&0xF;
3262 if(unsigned(ty) > swapbtn->d2)
3263 swapbtn->d1 &= ~0xF;
3264 swapbtn->dp3 = (void*)d;
3265 }
3266 int32_t ret = D_O_K;
3267 int32_t ntype = swapbtn->d1&0xF,
3268 otype = swapbtn->d1>>4;
3269
3270 char* str = (char*)d->dp;
3271 int32_t v = 0;
3272 if(msg == MSG_START)
3273 v = d->fg;
3274 else switch(otype)
3275 {
3276 case nswapDEC:
3277 v = atoi(str);
3278 break;
3279 case nswapHEX:
3280 v = zc_xtoi(str);
3281 break;
3282 }
3283 byte b;
3284 if ( v > 255 )
3285 b=255;
3286 else if ( v < 0 )
3287 b=0;
3288 else b = (byte)v;
3289 if(msg==MSG_CHAR && ((c&255)=='-'))
3290 {
3291 //unsigned//b = -b;
3292 c &= ~255;
3293 }
3294 if(unsigned(v) != b || otype != ntype || msg == MSG_START)
3295 {
3296 switch(ntype)
3297 {
3298 case nswapDEC:
3299 sprintf(str, "%d", b);
3300 break;
3301 case nswapHEX:
3302 sprintf(str, "%X", b);
3303 break;
3304 }
3305 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3306 }
3307
3308 if(d->fg != b)
3309 {
3310 d->fg = b; //Store numeric data
3311 GUI_EVENT(d, geUPDATE_SWAP);
3312 }
3313 switch(ntype)
3314 {
3315 case nswapDEC:
3316 d->d1 = 3; //3 digits max
3317 ret |= jwin_numedit_proc(msg, d, c);
3318 break;
3319 case nswapHEX:
3320 d->d1 = 2; //2 digits max
3321 if(msg == MSG_CHAR && isalpha(c&255)) //always capitalize
3322 c = (c&~255) | (toupper(c&255));
3323 ret |= jwin_hexedit_proc(msg, d, c);
3324 break;
3325 }
3326
3327 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3328
3329 return ret;
3330 }
3331 #define INC_TF_CURSORS(val,inc,max) \
3332 do \
3333 { \
3334 int32_t scursor = (val & 0xFFFF)+inc; \
3335 int32_t ecursor = (val & 0xFFFF0000) >> 16; \
3336 bool valid_ecursor = ecursor != 0xFFFF; \
3337 if(valid_ecursor) ecursor += inc; \
3338 if(inc < 0) \
3339 { \
3340 if(scursor < 0) scursor = 0; \
3341 if(valid_ecursor && ecursor < 0) ecursor = 0; \
3342 } \
3343 else \
3344 { \
3345 if(scursor > max) scursor = max; \
3346 if(valid_ecursor && ecursor > max) ecursor = max; \
3347 } \
3348 val = scursor | (ecursor<<16); \
3349 } while(false)
3350 int32_t jwin_numedit_swap_sshort_proc(int32_t msg, DIALOG *d, int32_t c)
3351 {
3352 const size_t maxlen = 7;
3353 DIALOG* swapbtn;
3354 if(d->flags&D_NEW_GUI)
3355 {
3356 swapbtn = d+1;
3357 }
3358 else swapbtn = (DIALOG*)d->dp3;
3359 if(!swapbtn) return D_O_K;
3360 if(msg==MSG_START) //Setup the swapbtn
3361 {
3362 d->bg = 0;
3363 swapbtn->d2 = 2; //Max states
3364 auto ty = swapbtn->d1&0xF;
3365 if(unsigned(ty) > swapbtn->d2)
3366 swapbtn->d1 &= ~0xF;
3367 swapbtn->dp3 = (void*)d;
3368 }
3369 int32_t ret = D_O_K;
3370 int32_t ntype = swapbtn->d1&0xF,
3371 otype = swapbtn->d1>>4;
3372
3373 char* str = (char*)d->dp;
3374 int32_t v = 0;
3375 if(msg == MSG_START)
3376 v = d->fg;
3377 else switch(otype)
3378 {
3379 case nswapDEC:
3380 v = atoi(str);
3381 break;
3382 case nswapHEX:
3383 v = zc_xtoi(str);
3384 break;
3385 }
3386 int16_t b;
3387 if ( v > 32767 )
3388 b=32767;
3389 else if ( v < -32768 )
3390 b=-32768;
3391 else b = (int16_t)v;
3392 bool queued_neg = d->bg;
3393 if(msg==MSG_CHAR && ((c&255)=='-'))
3394 {
3395 if(b)
3396 {
3397 b = -b;
3398 v = b;
3399 if(b<0)
3400 {
3401 if(str[0] != '-')
3402 {
3403 char buf[16] = {0};
3404 strcpy(buf, str);
3405 sprintf(str, "-%s", buf);
3406 INC_TF_CURSORS(d->d2,1,strlen(str));
3407 }
3408 }
3409 else if(str[0] == '-')
3410 {
3411 char buf[16] = {0};
3412 strcpy(buf, str);
3413 sprintf(str, "%s", buf+1);
3414 INC_TF_CURSORS(d->d2,-1,strlen(str));
3415 }
3416 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3417 }
3418 else queued_neg = !queued_neg; //queue the negative
3419 c &= ~255;
3420 ret |= D_USED_CHAR;
3421 }
3422 if(b && queued_neg)
3423 {
3424 //b = -b; //actually, 'atoi' handles it for us.....
3425 queued_neg = false;
3426 }
3427 if(bool(d->bg) != queued_neg)
3428 {
3429 d->bg = queued_neg;
3430 if(queued_neg)
3431 {
3432 if(str[0] != '-')
3433 {
3434 char buf[16] = {0};
3435 strcpy(buf, str);
3436 sprintf(str, "-%s", buf);
3437 INC_TF_CURSORS(d->d2,1,strlen(str));
3438 }
3439 }
3440 else if(!b && str[0] == '-')
3441 {
3442 char buf[16] = {0};
3443 strcpy(buf, str);
3444 sprintf(str, "%s", buf+1);
3445 INC_TF_CURSORS(d->d2,-1,strlen(str));
3446 }
3447 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3448 }
3449 if(v != b || otype != ntype || msg == MSG_START)
3450 {
3451 switch(ntype)
3452 {
3453 case nswapDEC:
3454 sprintf(str, "%d", b);
3455 break;
3456 case nswapHEX:
3457 if(b<0)
3458 sprintf(str, "-%X", -b);
3459 else sprintf(str, "%X", b);
3460 break;
3461 }
3462 d->d2 = 0xFFFF0000|strlen(str);
3463 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3464 }
3465
3466 if(d->fg != b)
3467 {
3468 d->fg = b; //Store numeric data
3469 GUI_EVENT(d, geUPDATE_SWAP);
3470 }
3471 bool rev_d2 = false;
3472 int32_t old_d2 = d->d2;
3473 int32_t ref_d2;
3474 if(msg == MSG_CHAR && queued_neg)
3475 {
3476 auto scursor = d->d2 & 0xFFFF;
3477 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
3478 if(!scursor)
3479 {
3480 rev_d2 = true;
3481 INC_TF_CURSORS(d->d2,1,strlen(str));
3482 ref_d2 = d->d2;
3483 }
3484 }
3485 switch(ntype)
3486 {
3487 case nswapDEC:
3488 d->d1 = 6; //6 digits max (incl '-')
3489 ret |= jwin_numedit_proc(msg, d, c);
3490 break;
3491 case nswapHEX:
3492 d->d1 = 5; //5 digits max (incl '-')
3493 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
3494 c = (c&~255) | (toupper(c&255));
3495 ret |= jwin_hexedit_proc(msg, d, c);
3496 break;
3497 }
3498 if(rev_d2 && ref_d2 == d->d2)
3499 {
3500 d->d2 = old_d2;
3501 }
3502
3503 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3504
3505 return ret;
3506 }
3507 int32_t jwin_numedit_swap_zsint_proc(int32_t msg, DIALOG *d, int32_t c)
3508 {
3509 const size_t maxlen = 13;
3510 DIALOG* swapbtn;
3511 if(d->flags&D_NEW_GUI)
3512 {
3513 swapbtn = d+1;
3514 }
3515 else swapbtn = (DIALOG*)d->dp3;
3516 if(!swapbtn) return D_O_K;
3517 if(msg==MSG_START) //Setup the swapbtn
3518 {
3519 d->bg = 0;
3520 swapbtn->d2 = 4; //Max states
3521 auto ty = swapbtn->d1&0xF;
3522 if(unsigned(ty) > swapbtn->d2)
3523 swapbtn->d1 &= ~0xF;
3524 swapbtn->dp3 = (void*)d;
3525 }
3526 int32_t ret = D_O_K;
3527 int32_t ntype = swapbtn->d1&0xF,
3528 otype = swapbtn->d1>>4;
3529
3530 char* str = (char*)d->dp;
3531 int64_t v = 0;
3532 if(msg == MSG_START)
3533 v = d->fg;
3534 else switch(otype)
3535 {
3536 case nswapDEC:
3537 if(char *ptr = strchr(str, '.'))
3538 {
3539 char tempstr[32] = {0};
3540 strcpy(tempstr, str);
3541 for(int32_t q = 0; q < 4; ++q)
3542 tempstr[strlen(str)+q]='0';
3543 ptr = strchr(tempstr, '.');
3544 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
3545 v = atoi(tempstr);
3546 v *= 10000;
3547 if(tempstr[0] == '-')
3548 v -= atoi(ptr);
3549 else v += atoi(ptr);
3550 }
3551 else
3552 {
3553 v = atoi(str);
3554 v *= 10000;
3555 }
3556 break;
3557 case nswapHEX:
3558 if(char *ptr = strchr(str, '.'))
3559 {
3560 char tempstr[32] = {0};
3561 strcpy(tempstr, str);
3562 for(int32_t q = 0; q < 4; ++q)
3563 tempstr[strlen(str)+q]='0';
3564 ptr = strchr(tempstr, '.');
3565 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
3566 v = zc_xtoi(tempstr);
3567 v *= 10000;
3568 if(tempstr[0] == '-')
3569 v -= atoi(ptr);
3570 else v += atoi(ptr);
3571 }
3572 else
3573 {
3574 v = zc_xtoi(str);
3575 v *= 10000;
3576 }
3577 break;
3578 case nswapLDEC:
3579 v = zc_atoi64(str);
3580 break;
3581 case nswapLHEX:
3582 v = zc_xtoi64(str);
3583 break;
3584 }
3585 int32_t b;
3586 if ( v > 2147483647 )
3587 b=2147483647;
3588 else if ( v < INT_MIN )
3589 b=INT_MIN;
3590 else b = (int32_t)v;
3591 bool queued_neg = d->bg;
3592 if(msg==MSG_CHAR && ((c&255)=='-'))
3593 {
3594 if(b)
3595 {
3596 if(b==INT_MIN)
3597 ++b;
3598 b = -b;
3599 v = b;
3600 if(b<0)
3601 {
3602 if(str[0] != '-')
3603 {
3604 char buf[16] = {0};
3605 strcpy(buf, str);
3606 sprintf(str, "-%s", buf);
3607 INC_TF_CURSORS(d->d2,1,strlen(str));
3608 }
3609 }
3610 else if(str[0] == '-')
3611 {
3612 char buf[16] = {0};
3613 strcpy(buf, str);
3614 sprintf(str, "%s", buf+1);
3615 INC_TF_CURSORS(d->d2,-1,strlen(str));
3616 }
3617 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3618 }
3619 else queued_neg = !queued_neg; //queue negative
3620 c &= ~255;
3621 ret |= D_USED_CHAR;
3622 }
3623 if(b && queued_neg)
3624 {
3625 //b = -b; //actually, 'atoi' handles it for us.....
3626 queued_neg = false;
3627 }
3628 if(bool(d->bg) != queued_neg)
3629 {
3630 d->bg = queued_neg;
3631 if(queued_neg)
3632 {
3633 if(str[0] != '-')
3634 {
3635 char buf[16] = {0};
3636 strcpy(buf, str);
3637 sprintf(str, "-%s", buf);
3638 INC_TF_CURSORS(d->d2,1,strlen(str));
3639 }
3640 }
3641 else if(!b && str[0] == '-')
3642 {
3643 char buf[16] = {0};
3644 strcpy(buf, str);
3645 sprintf(str, "%s", buf+1);
3646 INC_TF_CURSORS(d->d2,-1,strlen(str));
3647 }
3648 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3649 }
3650 if(v != b || otype != ntype || msg == MSG_START)
3651 {
3652 switch(ntype)
3653 {
3654 case nswapDEC:
3655 if(b < 0)
3656 sprintf(str, "-%ld.%04ld", abs(b/10000L), abs(b%10000L));
3657 else sprintf(str, "%ld.%04ld", b/10000L, b%10000L);
3658 trim_trailing_0s(str);
3659 break;
3660 case nswapHEX:
3661 if(b<0)
3662 sprintf(str, "-%lX.%04ld", abs(b/10000L), abs(b%10000L));
3663 else sprintf(str, "%lX.%04ld", b/10000L, abs(b%10000L));
3664 trim_trailing_0s(str);
3665 break;
3666 case nswapLDEC:
3667 sprintf(str, "%d", b);
3668 break;
3669 case nswapLHEX:
3670 if(b<0)
3671 sprintf(str, "-%X", -b);
3672 else sprintf(str, "%X", b);
3673 break;
3674 }
3675 d->d2 = 0xFFFF0000|strlen(str);
3676 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3677 }
3678 if(d->fg != b)
3679 {
3680 d->fg = b; //Store numeric data
3681 GUI_EVENT(d, geUPDATE_SWAP);
3682 }
3683 if(msg==MSG_CHAR && ((c&255)=='.'))
3684 {
3685 if(ntype >= nswapLDEC) //No '.' in long modes
3686 c&=~255;
3687 else
3688 {
3689 for(int32_t q = 0; str[q]; ++q)
3690 {
3691 if(str[q] == '.') //Only one '.'
3692 {
3693 c&=~255;
3694 break;
3695 }
3696 }
3697 }
3698 }
3699 bool rev_d2 = false;
3700 int32_t old_d2 = d->d2;
3701 int32_t ref_d2;
3702 if(msg == MSG_CHAR && queued_neg)
3703 {
3704 auto scursor = d->d2 & 0xFFFF;
3705 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
3706 if(!scursor)
3707 {
3708 rev_d2 = true;
3709 INC_TF_CURSORS(d->d2,1,strlen(str));
3710 ref_d2 = d->d2;
3711 }
3712 }
3713 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
3714 switch(ntype)
3715 {
3716 case nswapDEC:
3717 d->d1 = 12; //12 digits max (incl '-', '.')
3718 if(msg==MSG_CHAR && !editproc_special_key(c) && !areaselect)
3719 {
3720 int32_t p = 0;
3721 for(int32_t q = 0; str[q]; ++q)
3722 {
3723 if(str[q]=='.')
3724 {
3725 if((d->d2&0x0000FFFF) <= q)
3726 break; //typing before the '.'
3727 ++p;
3728 }
3729 else if(p) ++p;
3730 }
3731 if(p>=5) //too many chars after '.'
3732 c&=~255;
3733 }
3734 ret |= jwin_numedit_proc(msg, d, c);
3735 break;
3736 case nswapHEX:
3737 d->d1 = 11; //11 digits max (incl '-', '.')
3738 if(msg==MSG_CHAR && !editproc_special_key(c))
3739 {
3740 if(!((c&255)=='.'||isxdigit(c&255)))
3741 c&=~255;
3742 else if(isxdigit(c&255) && !isdigit(c&255))
3743 for(int32_t q = 0; q < (d->d2&0x0000FFFF) && str[q]; ++q)
3744 {
3745 if(str[q] == '.') //No hex digits to the right of the '.'
3746 {
3747 c&=~255;
3748 break;
3749 }
3750 }
3751 if((c&255) && !areaselect)
3752 {
3753 int32_t p = 0;
3754 for(int32_t q = 0; str[q]; ++q)
3755 {
3756 if(str[q]=='.')
3757 {
3758 if((d->d2&0x0000FFFF) <= q)
3759 break; //typing before the '.'
3760 ++p;
3761 }
3762 else if(p) ++p;
3763 }
3764 if(p>=5) //too many chars after '.'
3765 c&=~255;
3766 }
3767 if(isalpha(c&255)) //always capitalize
3768 c = (c&~255) | (toupper(c&255));
3769 }
3770 ret |= jwin_hexedit_proc(msg, d, c);
3771 break;
3772 case nswapLDEC:
3773 d->d1 = 11; //11 digits max (incl '-')
3774 ret |= jwin_numedit_proc(msg, d, c);
3775 break;
3776 case nswapLHEX:
3777 d->d1 = 9; //9 digits max (incl '-')
3778 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
3779 c = (c&~255) | (toupper(c&255));
3780 ret |= jwin_hexedit_proc(msg, d, c);
3781 break;
3782 }
3783 if(rev_d2 && ref_d2 == d->d2)
3784 {
3785 d->d2 = old_d2;
3786 }
3787
3788 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3789
3790 return ret;
3791 }
3792 int32_t jwin_numedit_swap_zsint_nodec_proc(int32_t msg, DIALOG *d, int32_t c)
3793 {
3794 const size_t maxlen = 7;
3795 DIALOG* swapbtn;
3796 if(d->flags&D_NEW_GUI)
3797 {
3798 swapbtn = d+1;
3799 }
3800 else swapbtn = (DIALOG*)d->dp3;
3801 if(!swapbtn) return D_O_K;
3802 if(msg==MSG_START) //Setup the swapbtn
3803 {
3804 d->bg = 0;
3805 swapbtn->d2 = 2; //Max states
3806 auto ty = swapbtn->d1&0xF;
3807 if(unsigned(ty) > swapbtn->d2)
3808 swapbtn->d1 &= ~0xF;
3809 swapbtn->dp3 = (void*)d;
3810 }
3811 int32_t ret = D_O_K;
3812 int32_t ntype = swapbtn->d1&0xF,
3813 otype = swapbtn->d1>>4;
3814
3815 char* str = (char*)d->dp;
3816 int64_t v = 0;
3817 if(msg == MSG_START)
3818 v = d->fg;
3819 else switch(otype)
3820 {
3821 case nswapDEC:
3822 v = atoi(str);
3823 v *= 10000;
3824 break;
3825 case nswapHEX:
3826 v = zc_xtoi(str);
3827 v *= 10000;
3828 break;
3829 }
3830 int32_t b;
3831 if ( v > 2147480000 )
3832 b=2147480000;
3833 else if ( v < -2147480000 )
3834 b=-2147480000;
3835 else b = (int32_t)v;
3836 bool queued_neg = d->bg;
3837 if(msg==MSG_CHAR && ((c&255)=='-'))
3838 {
3839 if(b)
3840 {
3841 if(b==INT_MIN)
3842 ++b;
3843 b = -b;
3844 v = b;
3845 if(b<0)
3846 {
3847 if(str[0] != '-')
3848 {
3849 char buf[16] = {0};
3850 strcpy(buf, str);
3851 sprintf(str, "-%s", buf);
3852 INC_TF_CURSORS(d->d2,1,strlen(str));
3853 }
3854 }
3855 else if(str[0] == '-')
3856 {
3857 char buf[16] = {0};
3858 strcpy(buf, str);
3859 sprintf(str, "%s", buf+1);
3860 INC_TF_CURSORS(d->d2,-1,strlen(str));
3861 }
3862 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3863 }
3864 else queued_neg = !queued_neg; //queue negative
3865 c &= ~255;
3866 ret |= D_USED_CHAR;
3867 }
3868 if(b && queued_neg)
3869 {
3870 //b = -b; //actually, 'atoi' handles it for us.....
3871 queued_neg = false;
3872 }
3873 if(bool(d->bg) != queued_neg)
3874 {
3875 d->bg = queued_neg;
3876 if(queued_neg)
3877 {
3878 if(str[0] != '-')
3879 {
3880 char buf[16] = {0};
3881 strcpy(buf, str);
3882 sprintf(str, "-%s", buf);
3883 INC_TF_CURSORS(d->d2,1,strlen(str));
3884 }
3885 }
3886 else if(!b && str[0] == '-')
3887 {
3888 char buf[16] = {0};
3889 strcpy(buf, str);
3890 sprintf(str, "%s", buf+1);
3891 INC_TF_CURSORS(d->d2,-1,strlen(str));
3892 }
3893 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3894 }
3895 if(v != b || otype != ntype || msg == MSG_START)
3896 {
3897 switch(ntype)
3898 {
3899 case nswapDEC:
3900 if(b < 0)
3901 sprintf(str, "-%ld", abs(b/10000L));
3902 else sprintf(str, "%ld", b/10000L);
3903 break;
3904 case nswapHEX:
3905 if(b<0)
3906 sprintf(str, "-%lX", abs(b/10000L));
3907 else sprintf(str, "%lX", b/10000L);
3908 break;
3909 }
3910 d->d2 = 0xFFFF0000|strlen(str);
3911 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3912 }
3913 if(d->fg != b)
3914 {
3915 d->fg = b; //Store numeric data
3916 GUI_EVENT(d, geUPDATE_SWAP);
3917 }
3918 if(msg==MSG_CHAR && ((c&255)=='.'))
3919 {
3920 c&=~255; //no '.' in nodec version
3921 }
3922 bool rev_d2 = false;
3923 int32_t old_d2 = d->d2;
3924 int32_t ref_d2;
3925 if(msg == MSG_CHAR && queued_neg)
3926 {
3927 auto scursor = d->d2 & 0xFFFF;
3928 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
3929 if(!scursor)
3930 {
3931 rev_d2 = true;
3932 INC_TF_CURSORS(d->d2,1,strlen(str));
3933 ref_d2 = d->d2;
3934 }
3935 }
3936 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
3937 switch(ntype)
3938 {
3939 case nswapDEC:
3940 d->d1 = 7; //7 digits max (incl '-')
3941 ret |= jwin_numedit_proc(msg, d, c);
3942 break;
3943 case nswapHEX:
3944 d->d1 = 6; //6 digits max (incl '-')
3945 if(msg==MSG_CHAR && !editproc_special_key(c))
3946 {
3947 if(!isxdigit(c&255))
3948 c&=~255;
3949 if(isalpha(c&255)) //always capitalize
3950 c = (c&~255) | (toupper(c&255));
3951 }
3952 ret |= jwin_hexedit_proc(msg, d, c);
3953 break;
3954 }
3955 if(rev_d2 && ref_d2 == d->d2)
3956 {
3957 d->d2 = old_d2;
3958 }
3959
3960 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3961
3962 return ret;
3963 }
3964 int32_t jwin_numedit_swap_zsint2_proc(int32_t msg, DIALOG *d, int32_t c)
3965 {
3966 const size_t maxlen = 13;
3967 DIALOG* swapbtn;
3968 ASSERT(d->flags&D_NEW_GUI);
3969 swapbtn = d+1;
3970 if(!swapbtn) return D_O_K;
3971 GUI::TextField *tf_obj = (GUI::TextField*)d->dp3;
3972 if(!tf_obj) return D_O_K;
3973 if(msg==MSG_START) //Setup the swapbtn
3974 {
3975 d->bg = 0;
3976 swapbtn->d2 = 5; //Max states
3977 auto ty = swapbtn->d1&0xF;
3978 if(unsigned(ty) > swapbtn->d2)
3979 swapbtn->d1 &= ~0xF;
3980 swapbtn->dp3 = (void*)d;
3981 }
3982 int32_t ret = D_O_K;
3983 int32_t ntype = swapbtn->d1&0xF,
3984 otype = swapbtn->d1>>4;
3985 if(otype==nswapBOOL || ntype == nswapBOOL)
3986 {
3987 if(otype != ntype)
3988 {
3989 tf_obj->refresh_cb_swap();
3990 }
3991 if(ntype == nswapBOOL)
3992 {
3993 swapbtn->d1 = (ntype<<4)|ntype;
3994 return D_O_K;
3995 }
3996 }
3997
3998 char* str = (char*)d->dp;
3999 int64_t v = 0;
4000 if(msg == MSG_START)
4001 v = d->fg;
4002 else switch(otype)
4003 {
4004 case nswapDEC:
4005 if(char *ptr = strchr(str, '.'))
4006 {
4007 char tempstr[32] = {0};
4008 strcpy(tempstr, str);
4009 for(int32_t q = 0; q < 4; ++q)
4010 tempstr[strlen(str)+q]='0';
4011 ptr = strchr(tempstr, '.');
4012 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4013 v = atoi(tempstr);
4014 v *= 10000;
4015 if(tempstr[0] == '-')
4016 v -= atoi(ptr);
4017 else v += atoi(ptr);
4018 }
4019 else
4020 {
4021 v = atoi(str);
4022 v *= 10000;
4023 }
4024 break;
4025 case nswapHEX:
4026 if(char *ptr = strchr(str, '.'))
4027 {
4028 char tempstr[32] = {0};
4029 strcpy(tempstr, str);
4030 for(int32_t q = 0; q < 4; ++q)
4031 tempstr[strlen(str)+q]='0';
4032 ptr = strchr(tempstr, '.');
4033 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4034 v = zc_xtoi(tempstr);
4035 v *= 10000;
4036 if(tempstr[0] == '-')
4037 v -= atoi(ptr);
4038 else v += atoi(ptr);
4039 }
4040 else
4041 {
4042 v = zc_xtoi(str);
4043 v *= 10000;
4044 }
4045 break;
4046 case nswapLDEC:
4047 v = zc_atoi64(str);
4048 break;
4049 case nswapLHEX:
4050 v = zc_xtoi64(str);
4051 break;
4052 case nswapBOOL:
4053 v = d->fg;
4054 break;
4055 }
4056 int32_t b;
4057 if ( v > 2147483647 )
4058 b=2147483647;
4059 else if ( v < INT_MIN )
4060 b=INT_MIN;
4061 else b = (int32_t)v;
4062 bool queued_neg = d->bg;
4063 if(msg==MSG_CHAR && ((c&255)=='-'))
4064 {
4065 if(b)
4066 {
4067 if(b==INT_MIN)
4068 ++b;
4069 b = -b;
4070 v = b;
4071 if(b<0)
4072 {
4073 if(str[0] != '-')
4074 {
4075 char buf[16] = {0};
4076 strcpy(buf, str);
4077 sprintf(str, "-%s", buf);
4078 INC_TF_CURSORS(d->d2,1,strlen(str));
4079 }
4080 }
4081 else if(str[0] == '-')
4082 {
4083 char buf[16] = {0};
4084 strcpy(buf, str);
4085 sprintf(str, "%s", buf+1);
4086 INC_TF_CURSORS(d->d2,-1,strlen(str));
4087 }
4088 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4089 }
4090 else queued_neg = !queued_neg; //queue negative
4091 c &= ~255;
4092 ret |= D_USED_CHAR;
4093 }
4094 if(b && queued_neg)
4095 {
4096 //b = -b; //actually, 'atoi' handles it for us.....
4097 queued_neg = false;
4098 }
4099 if(bool(d->bg) != queued_neg)
4100 {
4101 d->bg = queued_neg;
4102 if(queued_neg)
4103 {
4104 if(str[0] != '-')
4105 {
4106 char buf[16] = {0};
4107 strcpy(buf, str);
4108 sprintf(str, "-%s", buf);
4109 INC_TF_CURSORS(d->d2,1,strlen(str));
4110 }
4111 }
4112 else if(!b && str[0] == '-')
4113 {
4114 char buf[16] = {0};
4115 strcpy(buf, str);
4116 sprintf(str, "%s", buf+1);
4117 INC_TF_CURSORS(d->d2,-1,strlen(str));
4118 }
4119 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4120 }
4121 if(v != b || otype != ntype || msg == MSG_START)
4122 {
4123 switch(ntype)
4124 {
4125 case nswapDEC:
4126 if(b < 0)
4127 sprintf(str, "-%ld.%04ld", abs(b/10000L), abs(b%10000L));
4128 else sprintf(str, "%ld.%04ld", b/10000L, b%10000L);
4129 trim_trailing_0s(str);
4130 break;
4131 case nswapHEX:
4132 if(b<0)
4133 sprintf(str, "-%lX.%04ld", abs(b/10000L), abs(b%10000L));
4134 else sprintf(str, "%lX.%04ld", b/10000L, abs(b%10000L));
4135 trim_trailing_0s(str);
4136 break;
4137 case nswapLDEC:
4138 sprintf(str, "%d", b);
4139 break;
4140 case nswapLHEX:
4141 if(b<0)
4142 sprintf(str, "-%X", -b);
4143 else sprintf(str, "%X", b);
4144 break;
4145 }
4146 d->d2 = 0xFFFF0000|strlen(str);
4147 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4148 }
4149 if(d->fg != b)
4150 {
4151 d->fg = b; //Store numeric data
4152 GUI_EVENT(d, geUPDATE_SWAP);
4153 }
4154 if(msg==MSG_CHAR && ((c&255)=='.'))
4155 {
4156 if(ntype >= nswapLDEC) //No '.' in long modes
4157 c&=~255;
4158 else
4159 {
4160 for(int32_t q = 0; str[q]; ++q)
4161 {
4162 if(str[q] == '.') //Only one '.'
4163 {
4164 c&=~255;
4165 break;
4166 }
4167 }
4168 }
4169 }
4170 bool rev_d2 = false;
4171 int32_t old_d2 = d->d2;
4172 int32_t ref_d2;
4173 if(msg == MSG_CHAR && queued_neg)
4174 {
4175 auto scursor = d->d2 & 0xFFFF;
4176 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
4177 if(!scursor)
4178 {
4179 rev_d2 = true;
4180 INC_TF_CURSORS(d->d2,1,strlen(str));
4181 ref_d2 = d->d2;
4182 }
4183 }
4184 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
4185 switch(ntype)
4186 {
4187 case nswapDEC:
4188 d->d1 = 12; //12 digits max (incl '-', '.')
4189 if(msg==MSG_CHAR && !editproc_special_key(c) && !areaselect)
4190 {
4191 int32_t p = 0;
4192 for(int32_t q = 0; str[q]; ++q)
4193 {
4194 if(str[q]=='.')
4195 {
4196 if((d->d2&0x0000FFFF) <= q)
4197 break; //typing before the '.'
4198 ++p;
4199 }
4200 else if(p) ++p;
4201 }
4202 if(p>=5) //too many chars after '.'
4203 c&=~255;
4204 }
4205 ret |= jwin_numedit_proc(msg, d, c);
4206 break;
4207 case nswapHEX:
4208 d->d1 = 11; //11 digits max (incl '-', '.')
4209 if(msg==MSG_CHAR && !editproc_special_key(c))
4210 {
4211 if(!((c&255)=='.'||isxdigit(c&255)))
4212 c&=~255;
4213 else if(isxdigit(c&255) && !isdigit(c&255))
4214 for(int32_t q = 0; q < (d->d2&0x0000FFFF) && str[q]; ++q)
4215 {
4216 if(str[q] == '.') //No hex digits to the right of the '.'
4217 {
4218 c&=~255;
4219 break;
4220 }
4221 }
4222 if((c&255) && !areaselect)
4223 {
4224 int32_t p = 0;
4225 for(int32_t q = 0; str[q]; ++q)
4226 {
4227 if(str[q]=='.')
4228 {
4229 if((d->d2&0x0000FFFF) <= q)
4230 break; //typing before the '.'
4231 ++p;
4232 }
4233 else if(p) ++p;
4234 }
4235 if(p>=5) //too many chars after '.'
4236 c&=~255;
4237 }
4238 if(isalpha(c&255)) //always capitalize
4239 c = (c&~255) | (toupper(c&255));
4240 }
4241 ret |= jwin_hexedit_proc(msg, d, c);
4242 break;
4243 case nswapLDEC:
4244 d->d1 = 11; //11 digits max (incl '-')
4245 ret |= jwin_numedit_proc(msg, d, c);
4246 break;
4247 case nswapLHEX:
4248 d->d1 = 9; //9 digits max (incl '-')
4249 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
4250 c = (c&~255) | (toupper(c&255));
4251 ret |= jwin_hexedit_proc(msg, d, c);
4252 break;
4253 }
4254 if(rev_d2 && ref_d2 == d->d2)
4255 {
4256 d->d2 = old_d2;
4257 }
4258
4259 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
4260
4261 if(msg==MSG_START)
4262 tf_obj->refresh_cb_swap();
4263
4264 return ret;
4265 }
4266 int32_t jwin_numedit_noswap_zsint_proc(int32_t msg, DIALOG *d, int32_t c)
4267 {
4268 const size_t maxlen = 13;
4269 ASSERT(d->flags&D_NEW_GUI);
4270 GUI::TextField *tf_obj = (GUI::TextField*)d->dp3;
4271 if(!tf_obj) return D_O_K;
4272 int32_t ret = D_O_K;
4273 int32_t type = tf_obj->getSwapType();
4274
4275 char* str = (char*)d->dp;
4276 int64_t v = 0;
4277 if(msg == MSG_START)
4278 v = d->fg;
4279 else switch(type)
4280 {
4281 case nswapDEC:
4282 if(char *ptr = strchr(str, '.'))
4283 {
4284 char tempstr[32] = {0};
4285 strcpy(tempstr, str);
4286 for(int32_t q = 0; q < 4; ++q)
4287 tempstr[strlen(str)+q]='0';
4288 ptr = strchr(tempstr, '.');
4289 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4290 v = atoi(tempstr);
4291 v *= 10000;
4292 if(tempstr[0] == '-')
4293 v -= atoi(ptr);
4294 else v += atoi(ptr);
4295 }
4296 else
4297 {
4298 v = atoi(str);
4299 v *= 10000;
4300 }
4301 break;
4302 case nswapHEX:
4303 if(char *ptr = strchr(str, '.'))
4304 {
4305 char tempstr[32] = {0};
4306 strcpy(tempstr, str);
4307 for(int32_t q = 0; q < 4; ++q)
4308 tempstr[strlen(str)+q]='0';
4309 ptr = strchr(tempstr, '.');
4310 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4311 v = zc_xtoi(tempstr);
4312 v *= 10000;
4313 if(tempstr[0] == '-')
4314 v -= atoi(ptr);
4315 else v += atoi(ptr);
4316 }
4317 else
4318 {
4319 v = zc_xtoi(str);
4320 v *= 10000;
4321 }
4322 break;
4323 case nswapLDEC:
4324 v = zc_atoi64(str);
4325 break;
4326 case nswapLHEX:
4327 v = zc_xtoi64(str);
4328 break;
4329 case nswapBOOL:
4330 v = d->fg;
4331 break;
4332 }
4333 int32_t b;
4334 if ( v > 2147483647 )
4335 b=2147483647;
4336 else if ( v < INT_MIN )
4337 b=INT_MIN;
4338 else b = (int32_t)v;
4339 bool queued_neg = d->bg;
4340 if(msg==MSG_CHAR && ((c&255)=='-'))
4341 {
4342 if(b)
4343 {
4344 if(b==INT_MIN)
4345 ++b;
4346 b = -b;
4347 v = b;
4348 if(b<0)
4349 {
4350 if(str[0] != '-')
4351 {
4352 char buf[16] = {0};
4353 strcpy(buf, str);
4354 sprintf(str, "-%s", buf);
4355 INC_TF_CURSORS(d->d2,1,strlen(str));
4356 }
4357 }
4358 else if(str[0] == '-')
4359 {
4360 char buf[16] = {0};
4361 strcpy(buf, str);
4362 sprintf(str, "%s", buf+1);
4363 INC_TF_CURSORS(d->d2,-1,strlen(str));
4364 }
4365 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4366 }
4367 else queued_neg = !queued_neg; //queue negative
4368 c &= ~255;
4369 ret |= D_USED_CHAR;
4370 }
4371 if(b && queued_neg)
4372 {
4373 //b = -b; //actually, 'atoi' handles it for us.....
4374 queued_neg = false;
4375 }
4376 if(bool(d->bg) != queued_neg)
4377 {
4378 d->bg = queued_neg;
4379 if(queued_neg)
4380 {
4381 if(str[0] != '-')
4382 {
4383 char buf[16] = {0};
4384 strcpy(buf, str);
4385 sprintf(str, "-%s", buf);
4386 INC_TF_CURSORS(d->d2,1,strlen(str));
4387 }
4388 }
4389 else if(!b && str[0] == '-')
4390 {
4391 char buf[16] = {0};
4392 strcpy(buf, str);
4393 sprintf(str, "%s", buf+1);
4394 INC_TF_CURSORS(d->d2,-1,strlen(str));
4395 }
4396 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4397 }
4398 if(v != b || msg == MSG_START)
4399 {
4400 switch(type)
4401 {
4402 case nswapDEC:
4403 if(b < 0)
4404 sprintf(str, "-%ld.%04ld", abs(b/10000L), abs(b%10000L));
4405 else sprintf(str, "%ld.%04ld", b/10000L, b%10000L);
4406 trim_trailing_0s(str);
4407 break;
4408 case nswapHEX:
4409 if(b<0)
4410 sprintf(str, "-%lX.%04ld", abs(b/10000L), abs(b%10000L));
4411 else sprintf(str, "%lX.%04ld", b/10000L, abs(b%10000L));
4412 trim_trailing_0s(str);
4413 break;
4414 case nswapLDEC:
4415 sprintf(str, "%d", b);
4416 break;
4417 case nswapLHEX:
4418 if(b<0)
4419 sprintf(str, "-%X", -b);
4420 else sprintf(str, "%X", b);
4421 break;
4422 }
4423 d->d2 = 0xFFFF0000|strlen(str);
4424 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4425 }
4426 if(d->fg != b)
4427 {
4428 d->fg = b; //Store numeric data
4429 GUI_EVENT(d, geUPDATE_SWAP);
4430 }
4431 if(msg==MSG_CHAR && ((c&255)=='.'))
4432 {
4433 if(type >= nswapLDEC) //No '.' in long modes
4434 c&=~255;
4435 else
4436 {
4437 for(int32_t q = 0; str[q]; ++q)
4438 {
4439 if(str[q] == '.') //Only one '.'
4440 {
4441 c&=~255;
4442 break;
4443 }
4444 }
4445 }
4446 }
4447 bool rev_d2 = false;
4448 int32_t old_d2 = d->d2;
4449 int32_t ref_d2;
4450 if(msg == MSG_CHAR && queued_neg)
4451 {
4452 auto scursor = d->d2 & 0xFFFF;
4453 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
4454 if(!scursor)
4455 {
4456 rev_d2 = true;
4457 INC_TF_CURSORS(d->d2,1,strlen(str));
4458 ref_d2 = d->d2;
4459 }
4460 }
4461 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
4462 switch(type)
4463 {
4464 case nswapDEC:
4465 d->d1 = 12; //12 digits max (incl '-', '.')
4466 if(msg==MSG_CHAR && !editproc_special_key(c) && !areaselect)
4467 {
4468 int32_t p = 0;
4469 for(int32_t q = 0; str[q]; ++q)
4470 {
4471 if(str[q]=='.')
4472 {
4473 if((d->d2&0x0000FFFF) <= q)
4474 break; //typing before the '.'
4475 ++p;
4476 }
4477 else if(p) ++p;
4478 }
4479 if(p>=5) //too many chars after '.'
4480 c&=~255;
4481 }
4482 ret |= jwin_numedit_proc(msg, d, c);
4483 break;
4484 case nswapHEX:
4485 d->d1 = 11; //11 digits max (incl '-', '.')
4486 if(msg==MSG_CHAR && !editproc_special_key(c))
4487 {
4488 if(!((c&255)=='.'||isxdigit(c&255)))
4489 c&=~255;
4490 else if(isxdigit(c&255) && !isdigit(c&255))
4491 for(int32_t q = 0; q < (d->d2&0x0000FFFF) && str[q]; ++q)
4492 {
4493 if(str[q] == '.') //No hex digits to the right of the '.'
4494 {
4495 c&=~255;
4496 break;
4497 }
4498 }
4499 if((c&255) && !areaselect)
4500 {
4501 int32_t p = 0;
4502 for(int32_t q = 0; str[q]; ++q)
4503 {
4504 if(str[q]=='.')
4505 {
4506 if((d->d2&0x0000FFFF) <= q)
4507 break; //typing before the '.'
4508 ++p;
4509 }
4510 else if(p) ++p;
4511 }
4512 if(p>=5) //too many chars after '.'
4513 c&=~255;
4514 }
4515 if(isalpha(c&255)) //always capitalize
4516 c = (c&~255) | (toupper(c&255));
4517 }
4518 ret |= jwin_hexedit_proc(msg, d, c);
4519 break;
4520 case nswapLDEC:
4521 d->d1 = 11; //11 digits max (incl '-')
4522 ret |= jwin_numedit_proc(msg, d, c);
4523 break;
4524 case nswapLHEX:
4525 d->d1 = 9; //9 digits max (incl '-')
4526 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
4527 c = (c&~255) | (toupper(c&255));
4528 ret |= jwin_hexedit_proc(msg, d, c);
4529 break;
4530 }
4531 if(rev_d2 && ref_d2 == d->d2)
4532 {
4533 d->d2 = old_d2;
4534 }
4535
4536 if(msg==MSG_START)
4537 tf_obj->refresh_cb_swap();
4538
4539 return ret;
4540 }
4541
4542 /* _calc_scroll_bar:
4543 * Helps find positions of buttons on the scroll bar.
4544 */
4545 void _calc_scroll_bar(int32_t h, int32_t height, int32_t listsize, int32_t offset,
4546 int32_t *bh, int32_t *len, int32_t *pos)
4547 {
4548 *bh = zc_max(zc_min((h-4)/2, 14), 0);
4549 *len = zc_max(((h - 32) * height + listsize/2) / listsize , 6);
4550 *pos = ((h - 32 - *len) * offset) / (listsize-height);
4551 }
4552
4553 /* _handle_scrollable_click:
4554 * Helper to process a click on a scrollable object.
4555 */
4556
4557 void _handle_jwin_scrollable_scroll_click(DIALOG *d, int32_t listsize, int32_t *offset, FONT *fnt)
4558 {
4559 enum { top_btn, bottom_btn, bar, top_bar, bottom_bar };
4560
4561 int32_t xx, yy;
4562 int32_t height = (d->h-3) / (fnt ? text_height(fnt) : 1);
4563 int32_t hh = d->h - 32;
4564 int32_t obj = bar;
4565 int32_t bh, len, pos;
4566 int32_t down = 1, last_draw = 0;
4567 int32_t redraw = 0, mouse_delay = 0;
4568
4569 _calc_scroll_bar(d->h, height, listsize, *offset, &bh, &len, &pos);
4570
4571 xx = d->x + d->w - 18;
4572
4573 // find out which object is being clicked
4574
4575 yy = gui_mouse_y();
4576
4577 if(yy <= d->y+2+bh)
4578 {
4579 obj = top_btn;
4580 yy = d->y+2;
4581 }
4582 else if(yy >= d->y+d->h-2-bh)
4583 {
4584 obj = bottom_btn;
4585 yy = d->y+d->h-2-bh;
4586 }
4587 else if(d->h > 32+6)
4588 {
4589 if(yy < d->y+2+bh+pos)
4590 obj = top_bar;
4591 else if(yy >= d->y+2+bh+pos+len)
4592 obj = bottom_bar;
4593 }
4594
4595 while(gui_mouse_b())
4596 {
4597 _calc_scroll_bar(d->h, height, listsize, *offset, &bh, &len, &pos);
4598
4599 switch(obj)
4600 {
4601 case top_btn:
4602 case bottom_btn:
4603 down = mouse_in_rect(xx, yy, 16, bh);
4604
4605 if(!down)
4606 mouse_delay = 0;
4607 else
4608 {
4609 if((mouse_delay&1)==0)
4610 {
4611 if(obj==top_btn && *offset>0)
4612 {
4613 (*offset)--;
4614 redraw = 1;
4615 }
4616
4617 if(obj==bottom_btn && *offset<listsize-height)
4618 {
4619 (*offset)++;
4620 redraw = 1;
4621 }
4622 }
4623
4624 mouse_delay++;
4625 }
4626
4627 if(down!=last_draw || redraw)
4628 {
4629 vsync();
4630 d->proc(MSG_DRAW, d, 0);
4631 draw_arrow_button(screen, xx, yy, 16, bh, obj==top_btn, down*3);
4632 last_draw = down;
4633 }
4634
4635 break;
4636
4637 case top_bar:
4638 case bottom_bar:
4639 if(mouse_in_rect(xx, d->y+2, 16, d->h-4))
4640 {
4641 if(obj==top_bar)
4642 {
4643 if(gui_mouse_y() < d->y+2+bh+pos)
4644 yy = *offset - height;
4645 }
4646 else
4647 {
4648 if(gui_mouse_y() >= d->y+2+bh+pos+len)
4649 yy = *offset + height;
4650 }
4651
4652 if(yy < 0)
4653 yy = 0;
4654
4655 if(yy > listsize-height)
4656 yy = listsize-height;
4657
4658 if(yy != *offset)
4659 {
4660 *offset = yy;
4661 vsync();
4662 d->proc(MSG_DRAW, d, 0);
4663 }
4664 }
4665
4666 _calc_scroll_bar(d->h, height, listsize, *offset, &bh, &len, &pos);
4667
4668 if(!mouse_in_rect(xx, d->y+2+bh+pos, 16, len))
4669 break;
4670
4671 // fall through
4672
4673 case bar:
4674 default:
4675 xx = gui_mouse_y() - pos;
4676
4677 while(gui_mouse_b())
4678 {
4679 yy = (listsize * (gui_mouse_y() - xx) + hh/2) / hh;
4680
4681 if(yy > listsize-height)
4682 yy = listsize-height;
4683
4684 if(yy < 0)
4685 yy = 0;
4686
4687 bool should_redraw = false;
4688 if(yy != *offset)
4689 {
4690 *offset = yy;
4691 d->proc(MSG_DRAW, d, 0);
4692 should_redraw = true;
4693 }
4694
4695 /* let other objects continue to animate */
4696 int r = broadcast_dialog_message(MSG_IDLE, 0);
4697 if (r & D_REDRAWME) should_redraw = true;
4698
4699 if (should_redraw)
4700 {
4701 update_hw_screen();
4702 }
4703 }
4704
4705 break;
4706
4707 } // switch(obj)
4708
4709 redraw = 0;
4710
4711 update_hw_screen();
4712 // let other objects continue to animate
4713 broadcast_dialog_message(MSG_IDLE, 0);
4714 }
4715
4716 if(last_draw==1)
4717 {
4718 draw_arrow_button(screen, xx, yy, 16, bh, obj==top_btn, 0);
4719 }
4720 }
4721
4722 /* _handle_scrollable_scroll:
4723 * Helper function to scroll through a scrollable object.
4724 */
4725
4726 static void _handle_jwin_scrollable_scroll(DIALOG *d, int32_t listsize, int32_t *index, int32_t *offset, FONT *fnt)
4727 {
4728 int32_t height = (d->h-3) / text_height(fnt);
4729
4730 if(listsize <= 0)
4731 {
4732 *index = *offset = 0;
4733 return;
4734 }
4735
4736 // check selected item
4737 if(*index < 0)
4738 *index = 0;
4739 else if(*index >= listsize)
4740 *index = listsize - 1;
4741
4742 // check scroll position
4743 while((*offset > 0) && (*offset + height > listsize))
4744 (*offset)--;
4745
4746 if(*offset >= *index)
4747 {
4748 if(*index < 0)
4749 *offset = 0;
4750 else
4751 *offset = *index;
4752 }
4753 else
4754 {
4755 while((*offset + height - 1) < *index)
4756 (*offset)++;
4757 }
4758 }
4759
4760 /* idle_cb:
4761 * rest_callback() routine to keep dialogs animating nice and smoothly.
4762 */
4763
4764 static void idle_cb()
4765 {
4766 broadcast_dialog_message(MSG_IDLE, 0);
4767 }
4768
4769 /* _handle_listbox_click:
4770 * Helper to process a click on a listbox, doing hit-testing and moving
4771 * the selection.
4772 */
4773
4774 static bool _handle_jwin_listbox_click(DIALOG *d)
4775 {
4776 ListData *data = (ListData *)d->dp;
4777 char *sel = (char *)d->dp2;
4778 int32_t listsize, height;
4779 int32_t i, j;
4780
4781 data->listFunc(-1, &listsize);
4782
4783 if(!listsize)
4784 return false;
4785
4786 height = (d->h-3) / text_height(*data->font);
4787
4788 i = MID(0, ((gui_mouse_y() - d->y - 4) / text_height(*data->font)),
4789 ((d->h-3) / text_height(*data->font) - 1));
4790 i += d->d2;
4791
4792 if(i < d->d2)
4793 i = d->d2;
4794 else
4795 {
4796 if(i > d->d2 + height-1)
4797 i = d->d2 + height-1;
4798
4799 if(i >= listsize)
4800 i = listsize-1;
4801 }
4802
4803 if(gui_mouse_y() <= d->y)
4804 i = MAX(i-1, 0);
4805 else if(gui_mouse_y() >= d->y+d->h)
4806 i = MIN(i+1, listsize-1);
4807
4808 if(i != d->d1)
4809 {
4810 if(sel)
4811 {
4812 if(key_shifts & (KB_SHIFT_FLAG | KB_CTRL_CMD_FLAG))
4813 {
4814 if((key_shifts & KB_SHIFT_FLAG) || (d->flags & D_INTERNAL))
4815 {
4816 for(j=MIN(i, d->d1); j<=MAX(i, d->d1); j++)
4817 sel[j] = TRUE;
4818 }
4819 else
4820 sel[i] = TRUE;
4821 }
4822 }
4823
4824 d->d1 = i;
4825 i = d->d2;
4826
4827 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
4828
4829 object_message(d, MSG_DRAW, 0);
4830
4831 if(i != d->d2)
4832 rest_callback(MID(10, text_height(font)*16-d->h, 100), idle_cb);
4833 return true;
4834 }
4835 return false;
4836 }
4837
4838 /* _jwin_draw_scrollable_frame:
4839 * Helper function to draw a frame for all objects with vertical scrollbars.
4840 */
4841 void _jwin_draw_scrollable_frame(DIALOG *d, int32_t listsize, int32_t offset, int32_t height, int32_t type)
4842 {
4843 int32_t pos, len;
4844 int32_t xx, yy, hh, bh;
4845 static BITMAP *pattern = NULL; // just create it once
4846
4847 /* draw frame */
4848 if(type)
4849 // for droplists
4850 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DARK);
4851 else
4852 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DEEP);
4853
4854 /* possibly draw scrollbar */
4855 if(listsize > height)
4856 {
4857 _calc_scroll_bar(d->h, height, listsize, offset, &bh, &len, &pos);
4858
4859 xx = d->x + d->w - 18;
4860
4861 draw_arrow_button(screen, xx, d->y+2, 16, bh, 1, 0);
4862 draw_arrow_button(screen, xx, d->y+d->h-2-bh, 16, bh, 0, 0);
4863
4864 if(d->h > 32)
4865 {
4866 yy = d->y + 16;
4867 hh = (d->h-32);
4868
4869 /* create and draw the scrollbar */
4870 if(!pattern)
4871 pattern = create_bitmap_ex(bitmap_color_depth(screen),2,2);
4872
4873 putpixel(pattern, 0, 1, scheme[jcLIGHT]);
4874 putpixel(pattern, 1, 0, scheme[jcLIGHT]);
4875 putpixel(pattern, 0, 0, scheme[jcBOX]);
4876 putpixel(pattern, 1, 1, scheme[jcBOX]);
4877
4878 drawing_mode(DRAW_MODE_COPY_PATTERN, pattern, 0, 0);
4879 rectfill(screen, xx, yy, xx+15, yy+hh-1, 0);
4880 solid_mode();
4881
4882 if(d->h > 32+6)
4883 {
4884 jwin_draw_button(screen, xx, yy+pos, 16, len, 0, 1);
4885 }
4886 }
4887
4888 if(d->flags & D_GOTFOCUS)
4889 _dotted_rect(d->x+2, d->y+2, d->x+d->w-19, d->y+d->h-3, scheme[jcTEXTFG], scheme[jcTEXTBG]);
4890 }
4891 else if(d->flags & D_GOTFOCUS)
4892 _dotted_rect(d->x+2, d->y+2, d->x+d->w-3, d->y+d->h-3, scheme[jcTEXTFG], scheme[jcTEXTBG]);
4893 }
4894
4895 /*
4896 Effectively an overload of _jwin_draw_listbox that is used eclusively for file/abc listers.
4897 */
4898 void _jwin_draw_abclistbox(DIALOG *d)
4899 {
4900 int32_t height, listsize, i, len, bar, x, y, w;
4901 int32_t fg_color, bg_color, fg, bg;
4902 char *sel = (char*)d->dp2;
4903 char s[1024] = { 0 };
4904 ListData *data = (ListData *)d->dp;
4905
4906 FONT* oldfont = font;
4907 font = *data->font;
4908
4909 data->listFunc(-1, &listsize);
4910 height = (d->h-3) / text_height(font);
4911 bar = (listsize > height);
4912 w = (bar ? d->w-21 : d->w-5);
4913 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+d->h+9, scheme[jcBOX]);
4914 fg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : (d->fg ? d->fg : scheme[jcTEXTFG]);
4915 bg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_BG] : (d->bg ? d->bg : scheme[jcTEXTBG]);
4916
4917 rectfill(screen, d->x+2, d->y+2, d->x+w+2, d->y+3, bg_color);
4918 vline(screen, d->x+2, d->y+4, d->y+d->h-3, bg_color);
4919 vline(screen, d->x+3, d->y+4, d->y+d->h-3, bg_color);
4920 vline(screen, d->x+w+1, d->y+4, d->y+d->h-3, bg_color);
4921 vline(screen, d->x+w+2, d->y+4, d->y+d->h-3, bg_color);
4922 {
4923 rectfill(screen, d->x+1, d->y+d->h+2, d->x+d->w-2, d->y+1+d->h+text_height(font), bg_color);
4924 strncpy(s, abc_keypresses, 1023);
4925 char* s2 = s;
4926 int32_t tw = (d->w-1);
4927 while(text_length(font, s2) >= tw)
4928 {
4929 ++s2;
4930 }
4931 textout_ex(screen, font, s2, d->x+1, d->y+d->h+2,fg_color, bg_color);
4932 }
4933 //d->flags|=D_DIRTY;
4934
4935 /* draw box contents */
4936 for(i=0; i<height; i++)
4937 {
4938 if(d->d2+i < listsize)
4939 {
4940 if(d->d2+i == d->d1 && !(d->flags & D_DISABLED))
4941 {
4942 fg = scheme[jcSELFG];
4943 bg = scheme[jcSELBG];
4944 }
4945 else if((sel) && (sel[d->d2+i]))
4946 {
4947 fg = scheme[jcDISABLED_FG];
4948 bg = scheme[jcSELBG];
4949 }
4950 else
4951 {
4952 fg = fg_color;
4953 bg = bg_color;
4954 }
4955
4956 strncpy(s, data->listFunc(i+d->d2, NULL), 1023);
4957 x = d->x + 4;
4958 y = d->y + 4 + i*text_height(*data->font);
4959 // text_mode(bg);
4960 rectfill(screen, x, y, x+7, y+text_height(*data->font)-1, bg);
4961 x += 8;
4962 len = (int32_t)strlen(s);
4963
4964 while(text_length(*data->font, s) >= d->w - (bar ? 26 : 10))
4965 {
4966 len--;
4967 s[len] = 0;
4968 }
4969
4970 textout_ex(screen, *data->font, s, x, y, fg,bg);
4971 x += text_length(*data->font, s);
4972
4973 if(x <= d->x+w)
4974 rectfill(screen, x, y, d->x+w, y+text_height(*data->font)-1, bg);
4975 }
4976 else
4977 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
4978 d->x+w+2, d->y+3+(i+1)*text_height(*data->font), bg_color);
4979 }
4980
4981 if(d->y+4+i*text_height(font) <= d->y+d->h-3)
4982 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
4983 d->x+w+2, d->y+d->h-3, bg_color);
4984
4985 /* draw frame, maybe with scrollbar */
4986 _jwin_draw_scrollable_frame(d, listsize, d->d2, height, (d->flags&D_USER)?1:0);
4987
4988 font = oldfont;
4989 }
4990
4991 /* _jwin_draw_listbox:
4992 * Helper function to draw a listbox object.
4993 */
4994 void _jwin_draw_listbox(DIALOG *d)
4995 {
4996 int32_t height, listsize, i, len, bar, x, y, w;
4997 int32_t fg_color, bg_color, fg, bg;
4998 char *sel = (char*)d->dp2;
4999 char s[1024] = {0};
5000 ListData *data = (ListData *)d->dp;
5001
5002 data->listFunc(-1, &listsize);
5003 height = (d->h-3) / text_height(*data->font);
5004 bar = (listsize > height);
5005 w = (bar ? d->w-21 : d->w-5);
5006 fg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : (d->fg ? d->fg : scheme[jcTEXTFG]);
5007 bg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_BG] : (d->bg ? d->bg : scheme[jcTEXTBG]);
5008
5009 rectfill(screen, d->x+2, d->y+2, d->x+w+2, d->y+3, bg_color);
5010 vline(screen, d->x+2, d->y+4, d->y+d->h-3, bg_color);
5011 vline(screen, d->x+3, d->y+4, d->y+d->h-3, bg_color);
5012 vline(screen, d->x+w+1, d->y+4, d->y+d->h-3, bg_color);
5013 vline(screen, d->x+w+2, d->y+4, d->y+d->h-3, bg_color);
5014
5015 /* draw box contents */
5016 for(i=0; i<height; i++)
5017 {
5018 if(d->d2+i < listsize)
5019 {
5020 if(d->d2+i == d->d1 && !(d->flags & D_DISABLED))
5021 {
5022 fg = scheme[jcSELFG];
5023 bg = scheme[jcSELBG];
5024 }
5025 else if((sel) && (sel[d->d2+i]))
5026 {
5027 fg = scheme[jcMEDDARK];
5028 bg = scheme[jcSELBG];
5029 }
5030 else
5031 {
5032 fg = fg_color;
5033 bg = bg_color;
5034 }
5035
5036 strncpy(s, data->listFunc(i+d->d2, NULL), 1023);
5037 x = d->x + 4;
5038 y = d->y + 4 + i*text_height(*data->font);
5039 // text_mode(bg);
5040 rectfill(screen, x, y, x+7, y+text_height(*data->font)-1, bg);
5041 x += 8;
5042 len = (int32_t)strlen(s);
5043
5044 while(len > 0 && text_length(*data->font, s) >= d->w - (bar ? 26 : 10))
5045 {
5046 len--;
5047 s[len] = 0;
5048 }
5049
5050 textout_ex(screen, *data->font, s, x, y, fg,bg);
5051 x += text_length(*data->font, s);
5052
5053 if(x <= d->x+w)
5054 rectfill(screen, x, y, d->x+w, y+text_height(*data->font)-1, bg);
5055 }
5056 else
5057 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
5058 d->x+w+2, d->y+3+(i+1)*text_height(*data->font), bg_color);
5059 }
5060
5061 if(d->y+4+i*text_height(font) <= d->y+d->h-3)
5062 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
5063 d->x+w+2, d->y+d->h-3, bg_color);
5064
5065 /* draw frame, maybe with scrollbar */
5066 _jwin_draw_scrollable_frame(d, listsize, d->d2, height, (d->flags&D_USER)?1:0);
5067 }
5068
5069 /* jwin_list_proc:
5070 * A list box object. The dp field points to a ListData struct containing
5071 * a function which it will call
5072 * to obtain information about the list. This should follow the form:
5073 * char *<list_func_name> (int32_t index, int32_t *list_size);
5074 * If index is zero or positive, the function should return a pointer to
5075 * the string which is to be displayed at position index in the list. If
5076 * index is negative, it should return null and list_size should be set
5077 * to the number of items in the list. The list box object will allow the
5078 * user to scroll through the list and to select items list by clicking
5079 * on them, and if it has the input focus also by using the arrow keys. If
5080 * the D_EXIT flag is set, double clicking on a list item will cause it to
5081 * close the dialog. The index of the selected item is held in the d1
5082 * field, and d2 is used to store how far it has scrolled through the list.
5083 */
5084 int32_t jwin_list_proc(int32_t msg, DIALOG *d, int32_t c)
5085 {
5086 ListData *data = (ListData *)d->dp;
5087 int32_t listsize, i, bottom, height, bar, orig;
5088 char *sel = (char *)d->dp2;
5089 int32_t redraw = FALSE;
5090
5091 switch(msg)
5092 {
5093
5094 case MSG_START:
5095 data->listFunc(-1, &listsize);
5096 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5097 break;
5098
5099 case MSG_DRAW:
5100 _jwin_draw_listbox(d);
5101 break;
5102
5103 case MSG_CLICK:
5104 data->listFunc(-1, &listsize);
5105 height = (d->h-3) / text_height(*data->font);
5106 bar = (listsize > height);
5107
5108 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5109 {
5110 if((sel) && (!(key_shifts & KB_CTRL_CMD_FLAG)))
5111 {
5112 for(i=0; i<listsize; i++)
5113 {
5114 if(sel[i])
5115 {
5116 redraw = TRUE;
5117 sel[i] = FALSE;
5118 }
5119 }
5120
5121 if(redraw)
5122 {
5123 object_message(d, MSG_DRAW, 0);
5124 }
5125 }
5126
5127 if(_handle_jwin_listbox_click(d)) GUI_EVENT(d, geCHANGE_SELECTION);
5128
5129 bool rightClicked=(gui_mouse_b()&2)!=0;
5130 while(gui_mouse_b())
5131 {
5132 broadcast_dialog_message(MSG_IDLE, 0);
5133 d->flags |= D_INTERNAL;
5134 bool should_redraw = false;
5135 if(_handle_jwin_listbox_click(d))
5136 {
5137 d->flags &= ~D_INTERNAL;
5138 GUI_EVENT(d, geCHANGE_SELECTION);
5139 should_redraw = true;
5140 }
5141 d->flags &= ~D_INTERNAL;
5142
5143 /* let other objects continue to animate */
5144 int r = broadcast_dialog_message(MSG_IDLE, 0);
5145 if (r & D_REDRAWME) should_redraw = true;
5146
5147 if (should_redraw)
5148 {
5149 update_hw_screen();
5150 }
5151 }
5152
5153 if(rightClicked)
5154 {
5155 GUI_EVENT(d, geRCLICK);
5156 if((d->flags&(D_USER<<1))!=0 && d->dp3)
5157 {
5158 typedef void (*funcType)(int32_t /* index */, int32_t /* x */, int32_t /* y */);
5159 funcType func=reinterpret_cast<funcType>(d->dp3);
5160 func(d->d1, gui_mouse_x(), gui_mouse_y());
5161 }
5162 }
5163
5164 if(d->flags & D_USER)
5165 {
5166 if(listsize)
5167 {
5168 clear_keybuf();
5169 return D_CLOSE;
5170 }
5171 }
5172
5173 return D_REDRAWME;
5174 }
5175 else
5176 {
5177 _handle_jwin_scrollable_scroll_click(d, listsize, &d->d2, *data->font);
5178 }
5179
5180 break;
5181
5182 case MSG_DCLICK:
5183 // Ignore double right-click
5184 if((gui_mouse_b()&2)!=0)
5185 break;
5186
5187 data->listFunc(-1, &listsize);
5188 height = (d->h-3) / text_height(*data->font);
5189 bar = (listsize > height);
5190
5191 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5192 {
5193 if(listsize)
5194 {
5195 i = d->d1;
5196 object_message(d, MSG_CLICK, 0);
5197
5198 if(i == d->d1)
5199 {
5200 if(d->flags & D_EXIT)
5201 return D_CLOSE;
5202 else GUI_EVENT(d, geDCLICK);
5203 }
5204 }
5205 }
5206
5207 break;
5208
5209 case MSG_KEY:
5210 data->listFunc(-1, &listsize);
5211
5212 if((listsize) && (d->flags & D_EXIT))
5213 return D_CLOSE;
5214
5215 break;
5216
5217 case MSG_WANTFOCUS:
5218 return D_WANTFOCUS;
5219
5220 case MSG_WANTWHEEL:
5221 return 1;
5222
5223 case MSG_WHEEL:
5224 data->listFunc(-1, &listsize);
5225 height = (d->h-4) / text_height(*data->font);
5226
5227 if(height < listsize)
5228 {
5229 int32_t delta = (height > 3) ? 3 : 1;
5230
5231 if(c > 0)
5232 {
5233 i = MAX(0, d->d2-delta);
5234 }
5235 else
5236 {
5237 i = MIN(listsize-height, d->d2+delta);
5238 }
5239
5240 if(i != d->d2)
5241 {
5242 d->d2 = i;
5243 object_message(d, MSG_DRAW, 0);
5244 GUI_EVENT(d, geCHANGE_SELECTION);
5245 return D_REDRAWME;
5246 }
5247 }
5248
5249 break;
5250
5251 case MSG_CHAR:
5252 data->listFunc(-1,&listsize);
5253
5254 if(listsize)
5255 {
5256 c >>= 8;
5257
5258 bottom = d->d2 + (d->h-3)/text_height(*data->font) - 1;
5259
5260 if(bottom >= listsize-1)
5261 bottom = listsize-1;
5262
5263 orig = d->d1;
5264
5265 if(c == KEY_UP)
5266 d->d1--;
5267 else if(c == KEY_DOWN)
5268 d->d1++;
5269 else if(c == KEY_HOME)
5270 d->d1 = 0;
5271 else if(c == KEY_END)
5272 d->d1 = listsize-1;
5273 else if(c == KEY_PGUP)
5274 {
5275 if(d->d1 > d->d2)
5276 d->d1 = d->d2;
5277 else
5278 d->d1 -= (bottom - d->d2);
5279 }
5280 else if(c == KEY_PGDN)
5281 {
5282 if(d->d1 < bottom)
5283 d->d1 = bottom;
5284 else
5285 d->d1 += (bottom - d->d2);
5286 }
5287 else
5288 return D_O_K;
5289
5290 if(sel)
5291 {
5292 if(!(key_shifts & (KB_SHIFT_FLAG | KB_CTRL_CMD_FLAG)))
5293 {
5294 for(i=0; i<listsize; i++)
5295 sel[i] = FALSE;
5296 }
5297 else if(key_shifts & KB_SHIFT_FLAG)
5298 {
5299 for(i=MIN(orig, d->d1); i<=MAX(orig, d->d1); i++)
5300 {
5301 if(key_shifts & KB_CTRL_CMD_FLAG)
5302 sel[i] = (i != d->d1);
5303 else
5304 sel[i] = TRUE;
5305 }
5306 }
5307 }
5308
5309 /* if we changed something, better redraw... !Also bounds the index! */
5310 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5311
5312 GUI_EVENT(d, geCHANGE_SELECTION);
5313
5314 if (d->d1 != orig)
5315 d->flags |= D_DIRTY;
5316 return D_USED_CHAR;
5317 }
5318
5319 break;
5320 }
5321
5322 return D_O_K;
5323 }
5324
5325
5326 /*
5327 Effectively an overload of jwin_list_proc that i used eclusively for abc lists.
5328 This calls the appropriate form of drawing for those listers.
5329 */
5330 int32_t jwin_do_abclist_proc(int32_t msg, DIALOG *d, int32_t c)
5331 {
5332 ListData *data = (ListData *)d->dp;
5333 int32_t listsize, i, bottom, height, bar, orig, h;
5334 int32_t ret = D_O_K;
5335 bool revert_size = false;
5336 if((d->flags & D_RESIZED) == 0)
5337 {
5338 h = d->h;
5339 d->h -= text_height(*data->font);
5340 d->flags |= D_RESIZED;
5341 revert_size = true;
5342 }
5343 char *sel = (char *)d->dp2;
5344 int32_t redraw = FALSE;
5345
5346 switch(msg)
5347 {
5348
5349 case MSG_START:
5350 data->listFunc(-1, &listsize);
5351 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5352 break;
5353
5354 case MSG_DRAW:
5355 _jwin_draw_abclistbox(d);
5356 break;
5357
5358 case MSG_CLICK:
5359 if(gui_mouse_y() > (d->y+d->h-1))
5360 {
5361 if(gui_mouse_y() > (d->y+d->h+2))
5362 {
5363 //Clicked on the box displaying the patternmatch
5364 }
5365 else {} //Clicked between the lister and patternmatch
5366 }
5367 else //Clicked the lister
5368 {
5369 data->listFunc(-1, &listsize);
5370 height = (d->h-3) / text_height(*data->font);
5371 bar = (listsize > height);
5372
5373 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5374 {
5375 if((sel) && (!(key_shifts & KB_CTRL_CMD_FLAG)))
5376 {
5377 for(i=0; i<listsize; i++)
5378 {
5379 if(sel[i])
5380 {
5381 redraw = TRUE;
5382 sel[i] = FALSE;
5383 }
5384 }
5385
5386 if(redraw)
5387 {
5388 object_message(d, MSG_DRAW, 0);
5389 }
5390 }
5391
5392 if(_handle_jwin_listbox_click(d)) GUI_EVENT(d, geCHANGE_SELECTION);
5393
5394 bool rightClicked=(gui_mouse_b()&2)!=0;
5395 while(gui_mouse_b())
5396 {
5397 broadcast_dialog_message(MSG_IDLE, 0);
5398 d->flags |= D_INTERNAL;
5399 if(_handle_jwin_listbox_click(d))
5400 {
5401 d->flags &= ~D_INTERNAL;
5402 GUI_EVENT(d, geCHANGE_SELECTION);
5403 update_hw_screen();
5404 }
5405 d->flags &= ~D_INTERNAL;
5406 rest(1);
5407 }
5408
5409 if(rightClicked)
5410 {
5411 GUI_EVENT(d, geRCLICK);
5412 if((d->flags&(D_USER<<1))!=0 && d->dp3)
5413 {
5414 typedef void (*funcType)(int32_t /* index */, int32_t /* x */, int32_t /* y */);
5415 funcType func=reinterpret_cast<funcType>(d->dp3);
5416 func(d->d1, gui_mouse_x(), gui_mouse_y());
5417 }
5418 }
5419
5420 if(d->flags & D_USER)
5421 {
5422 if(listsize)
5423 {
5424 clear_keybuf();
5425 ret = D_CLOSE;
5426 }
5427 }
5428
5429 return D_REDRAWME;
5430 }
5431 else
5432 {
5433 _handle_jwin_scrollable_scroll_click(d, listsize, &d->d2, *data->font);
5434 }
5435 }
5436 break;
5437
5438 case MSG_DCLICK:
5439 // Ignore double right-click
5440 if((gui_mouse_b()&2)!=0)
5441 break;
5442
5443 if(gui_mouse_y() > (d->y+d->h-1))
5444 {
5445 if(gui_mouse_y() > (d->y+d->h+2))
5446 {
5447 //Clicked on the box displaying the patternmatch
5448 }
5449 else {} //Clicked between the lister and patternmatch
5450 }
5451 else //Clicked the lister
5452 {
5453 data->listFunc(-1, &listsize);
5454 height = (d->h-3) / text_height(*data->font);
5455 bar = (listsize > height);
5456
5457 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5458 {
5459 if(listsize)
5460 {
5461 i = d->d1;
5462 object_message(d, MSG_CLICK, 0);
5463
5464 if(i == d->d1)
5465 {
5466 if(d->flags & D_EXIT)
5467 ret = D_CLOSE;
5468 else GUI_EVENT(d, geDCLICK);
5469 }
5470 }
5471 }
5472 }
5473 break;
5474
5475 case MSG_KEY:
5476 data->listFunc(-1, &listsize);
5477
5478 if((listsize) && (d->flags & D_EXIT))
5479 ret = D_CLOSE;
5480
5481 break;
5482
5483 case MSG_WANTFOCUS:
5484 ret = D_WANTFOCUS;
5485 break;
5486
5487 case MSG_WANTWHEEL:
5488 return 1;
5489
5490 case MSG_WHEEL:
5491 data->listFunc(-1, &listsize);
5492 height = (d->h-4) / text_height(*data->font);
5493
5494 if(height < listsize)
5495 {
5496 int32_t delta = (height > 3) ? 3 : 1;
5497
5498 if(c > 0)
5499 {
5500 i = MAX(0, d->d2-delta);
5501 }
5502 else
5503 {
5504 i = MIN(listsize-height, d->d2+delta);
5505 }
5506
5507 if(i != d->d2)
5508 {
5509 d->d2 = i;
5510 object_message(d, MSG_DRAW, 0);
5511 GUI_EVENT(d, geCHANGE_SELECTION);
5512 ret |= D_REDRAWME;
5513 }
5514 }
5515
5516 break;
5517
5518 case MSG_CHAR:
5519 data->listFunc(-1,&listsize);
5520
5521 if(listsize)
5522 {
5523 c >>= 8;
5524
5525 bottom = d->d2 + (d->h-3)/text_height(*data->font) - 1;
5526
5527 if(bottom >= listsize-1)
5528 bottom = listsize-1;
5529
5530 orig = d->d1;
5531
5532 if(c == KEY_UP)
5533 d->d1--;
5534 else if(c == KEY_DOWN)
5535 d->d1++;
5536 else if(c == KEY_HOME)
5537 d->d1 = 0;
5538 else if(c == KEY_END)
5539 d->d1 = listsize-1;
5540 else if(c == KEY_PGUP)
5541 {
5542 if(d->d1 > d->d2)
5543 d->d1 = d->d2;
5544 else
5545 d->d1 -= (bottom - d->d2);
5546 }
5547 else if(c == KEY_PGDN)
5548 {
5549 if(d->d1 < bottom)
5550 d->d1 = bottom;
5551 else
5552 d->d1 += (bottom - d->d2);
5553 }
5554 else
5555 break; //return D_O_K;
5556
5557 if(sel)
5558 {
5559 if(!(key_shifts & (KB_SHIFT_FLAG | KB_CTRL_CMD_FLAG)))
5560 {
5561 for(i=0; i<listsize; i++)
5562 sel[i] = FALSE;
5563 }
5564 else if(key_shifts & KB_SHIFT_FLAG)
5565 {
5566 for(i=MIN(orig, d->d1); i<=MAX(orig, d->d1); i++)
5567 {
5568 if(key_shifts & KB_CTRL_CMD_FLAG)
5569 sel[i] = (i != d->d1);
5570 else
5571 sel[i] = TRUE;
5572 }
5573 }
5574 }
5575
5576 /* if we changed something, better redraw... */
5577 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5578
5579 GUI_EVENT(d, geCHANGE_SELECTION);
5580
5581 if (d->d1 != orig)
5582 d->flags |= D_DIRTY;
5583 ret = D_USED_CHAR;
5584 }
5585
5586 break;
5587 }
5588 if(revert_size)
5589 {
5590 d->h = h;
5591 d->flags &= ~D_RESIZED;
5592 }
5593 return ret;
5594 }
5595
5596 /* _jwin_draw_textbox:
5597 * Helper function to draw a textbox object.
5598 */
5599 void _jwin_draw_textbox(char *thetext, int32_t *listsize, int32_t draw, int32_t offset,
5600 int32_t wword, int32_t tabsize, int32_t x, int32_t y, int32_t w, int32_t h,
5601 int32_t disabled)
5602 {
5603 int32_t fg = scheme[jcTEXTFG];
5604 int32_t bg = scheme[jcTEXTBG];
5605 int32_t y1 = y+4;
5606 int32_t x1;
5607 int32_t len;
5608 int32_t ww = w-10;
5609 char s[16] = {0};
5610 char text[16] = {0};
5611 char space[16] = {0};
5612 char *printed = text;
5613 char *scanned = text;
5614 char *oldscan = text;
5615 char *ignore = NULL;
5616 char *tmp, *ptmp;
5617 int32_t width;
5618 int32_t line = 0;
5619 int32_t i = 0;
5620 int32_t noignore;
5621 // int32_t rtm;
5622
5623 usetc(s+usetc(s, '.'), 0);
5624 usetc(text+usetc(text, ' '), 0);
5625 usetc(space+usetc(space, ' '), 0);
5626
5627 /* find the correct text */
5628 if(thetext != NULL)
5629 {
5630 printed = thetext;
5631 scanned = thetext;
5632 }
5633
5634 /* choose the text color */
5635 if(disabled)
5636 {
5637 fg = scheme[jcDISABLED_FG];
5638 bg = scheme[jcDISABLED_BG];
5639 }
5640
5641 /* do some drawing setup */
5642 if(draw)
5643 {
5644 /* initial start blanking at the top */
5645 rectfill(screen, x+2, y+2, x+w-2, y1-1, bg);
5646 }
5647
5648 // rtm = text_mode(bg);
5649
5650 /* loop over the entire string */
5651 for(;;)
5652 {
5653 width = 0;
5654
5655 /* find the next break */
5656 while(ugetc(scanned))
5657 {
5658 /* check for a forced break */
5659 if(ugetc(scanned) == '\n')
5660 {
5661 scanned += uwidth(scanned);
5662
5663 /* we are done parsing the line end */
5664 break;
5665 }
5666
5667 /* the next character length */
5668 usetc(s+usetc(s, ugetc(scanned)), 0);
5669 len = text_length(font, s);
5670
5671 /* modify length if its a tab */
5672 if(ugetc(s) == '\t')
5673 len = tabsize * text_length(font, space);
5674
5675 /* check for the end of a line by excess width of next char */
5676 if(width+len >= ww)
5677 {
5678 /* we have reached end of line do we go back to find start */
5679 if(wword)
5680 {
5681 /* remember where we were */
5682 oldscan = scanned;
5683 noignore = FALSE;
5684
5685 /* go backwards looking for start of word */
5686 while(!uisspace(ugetc(scanned)))
5687 {
5688 /* don't wrap too far */
5689 if(scanned == printed)
5690 {
5691 /* the whole line is filled, so stop here */
5692 tmp = ptmp = scanned;
5693
5694 while(ptmp != oldscan)
5695 {
5696 ptmp = tmp;
5697 tmp += uwidth(tmp);
5698 }
5699
5700 scanned = ptmp;
5701 noignore = TRUE;
5702 break;
5703 }
5704
5705 /* look further backwards to wrap */
5706 tmp = ptmp = printed;
5707
5708 while(tmp < scanned)
5709 {
5710 ptmp = tmp;
5711 tmp += uwidth(tmp);
5712 }
5713
5714 scanned = ptmp;
5715 }
5716
5717 /* put the space at the end of the line */
5718 if(!noignore)
5719 {
5720 ignore = scanned;
5721 scanned += uwidth(scanned);
5722 }
5723 else
5724 ignore = NULL;
5725
5726 /* check for endline at the convenient place */
5727 if(ugetc(scanned) == '\n')
5728 scanned += uwidth(scanned);
5729 }
5730
5731 /* we are done parsing the line end */
5732 break;
5733 }
5734
5735 /* the character can be added */
5736 scanned += uwidth(scanned);
5737 width += len;
5738 }
5739
5740 /* check if we are to print it */
5741 if((draw) && (line >= offset) && (y1+text_height(font) < (y+h-3)))
5742 {
5743 x1 = x+4;
5744
5745 /* the initial blank bit */
5746 rectfill(screen, x+2, y1, x1-1, y1+text_height(font), bg);
5747
5748 /* print up to the marked character */
5749 while(printed != scanned)
5750 {
5751 /* do special stuff for each character */
5752 switch(ugetc(printed))
5753 {
5754
5755 case '\r':
5756 case '\n':
5757 /* don't print endlines in the text */
5758 break;
5759
5760 /* possibly expand the tabs */
5761 case '\t':
5762 for(i=0; i<tabsize; i++)
5763 {
5764 usetc(s+usetc(s, ' '), 0);
5765 textout_ex(screen, font, s, x1, y1, fg,bg);
5766 x1 += text_length(font, s);
5767 }
5768
5769 break;
5770
5771 /* print a normal character */
5772 default:
5773 if(printed != ignore)
5774 {
5775 usetc(s+usetc(s, ugetc(printed)), 0);
5776 textout_ex(screen, font, s, x1, y1, fg,bg);
5777 x1 += text_length(font, s);
5778 }
5779 }
5780
5781 /* goto the next character */
5782 printed += uwidth(printed);
5783 }
5784
5785 /* the last blank bit */
5786 if(x1 <= x+w-3)
5787 rectfill(screen, x1, y1, x+w-2, y1+text_height(font)-1, bg);
5788
5789 /* print the line end */
5790 y1 += text_height(font);
5791 }
5792
5793 printed = scanned;
5794
5795 /* we have done a line */
5796 line++;
5797
5798 /* check if we are at the end of the string */
5799 if(!ugetc(printed))
5800 {
5801 /* the under blank bit */
5802 if(draw)
5803 rectfill(screen, x+1, y1, x+w-2, y+h-1, bg);
5804
5805 /* tell how many lines we found */
5806 *listsize = line;
5807 // text_mode(rtm);
5808 return;
5809 }
5810 }
5811
5812 // text_mode(rtm);
5813 }
5814
5815 /* jwin_textbox_proc:
5816 * A text box object. The dp field points to a char * which is the text
5817 * to be displayed in the text box. If the text is long, there will be
5818 * a vertical scrollbar on the right hand side of the object which can
5819 * be used to scroll through the text. The default is to print the text
5820 * with word wrapping, but if the D_SELECTED flag is set, the text will
5821 * be printed with character wrapping. The d1 field is used internally
5822 * to store the number of lines of text, and d2 is used to store how far
5823 * it has scrolled through the text.
5824 */
5825 int32_t jwin_textbox_proc(int32_t msg, DIALOG *d, int32_t c)
5826 {
5827 int32_t height, bar, ret = D_O_K;
5828 int32_t start, top, bottom,l;
5829 int32_t used, delta;
5830 // int32_t fg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
5831
5832 FONT *oldfont=NULL;
5833
5834 if(d->dp2!=NULL)
5835 {
5836 oldfont=font;
5837 font=(FONT*)d->dp2;
5838 }
5839
5840 /* calculate the actual height */
5841 height = (d->h-4) / text_height(font);
5842
5843 switch(msg)
5844 {
5845
5846 case MSG_START:
5847 /* measure how many lines of text we contain */
5848 _jwin_draw_textbox((char*)d->dp, &d->d1,
5849 0, /* DONT DRAW anything */
5850 d->d2, !(d->flags & D_SELECTED), 8,
5851 d->x, d->y, d->w, d->h,
5852 (d->flags & D_DISABLED));
5853 break;
5854
5855 case MSG_DRAW:
5856 /* tell the object to sort of draw, but only calculate the listsize */
5857 _jwin_draw_textbox((char*)d->dp, &d->d1,
5858 0, /* DONT DRAW anything */
5859 d->d2, !(d->flags & D_SELECTED), 8,
5860 d->x, d->y, d->w, d->h,
5861 (d->flags & D_DISABLED));
5862
5863 if(d->d1 > height)
5864 {
5865 bar = 16;
5866 }
5867 else
5868 {
5869 bar = 0;
5870 d->d2 = 0;
5871 }
5872
5873 /* now do the actual drawing */
5874 _jwin_draw_textbox((char*)d->dp, &d->d1, 1, d->d2,
5875 !(d->flags & D_SELECTED), 8,
5876 d->x, d->y, d->w-bar-1, d->h,
5877 (d->flags & D_DISABLED));
5878
5879 /* draw the frame around */
5880 _jwin_draw_scrollable_frame(d, d->d1, d->d2, height, 0);
5881 break;
5882
5883 case MSG_CLICK:
5884 /* figure out if it's on the text or the scrollbar */
5885 bar = (d->d1 > height);
5886
5887 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5888 {
5889 /* clicked on the text area */
5890 ret = D_O_K;
5891 }
5892 else
5893 {
5894 /* clicked on the scroll area */
5895 _handle_jwin_scrollable_scroll_click(d, d->d1, &d->d2, font);
5896 }
5897
5898 break;
5899
5900 case MSG_WANTWHEEL:
5901 return 1;
5902
5903 case MSG_WHEEL:
5904 l = (d->h-8)/text_height(font);
5905 delta = (l > 3) ? 3 : 1;
5906
5907 // scroll, making sure that the list stays in bounds
5908 start = d->d2;
5909 d->d2 = (c > 0) ? MAX(0, d->d2-delta) : MIN(d->d1-l, d->d2+delta);
5910
5911 // if we changed something, better redraw...
5912 if(d->d2 != start)
5913 {
5914 d->flags |= D_DIRTY;
5915 }
5916
5917 ret = D_O_K;
5918 break;
5919
5920 case MSG_CHAR:
5921 start = d->d2;
5922 used = D_USED_CHAR;
5923
5924 if(d->d1 > 0)
5925 {
5926 if(d->d2 > 0)
5927 top = d->d2+1;
5928 else
5929 top = 0;
5930
5931 l = (d->h-3)/text_height(font);
5932
5933 bottom = d->d2 + l - 1;
5934
5935 if(bottom >= d->d1-1)
5936 bottom = d->d1-1;
5937 else
5938 bottom--;
5939
5940 if((c>>8) == KEY_UP)
5941 d->d2--;
5942 else if((c>>8) == KEY_DOWN)
5943 d->d2++;
5944 else if((c>>8) == KEY_HOME)
5945 d->d2 = 0;
5946 else if((c>>8) == KEY_END)
5947 d->d2 = d->d1-l;
5948 else if((c>>8) == KEY_PGUP)
5949 d->d2 = d->d2-(bottom-top);
5950 else if((c>>8) == KEY_PGDN)
5951 d->d2 = d->d2+(bottom-top);
5952 else
5953 used = D_O_K;
5954
5955 /* make sure that the list stays in bounds */
5956 if(d->d2 > d->d1-l)
5957 d->d2 = d->d1-l;
5958
5959 if(d->d2 < 0)
5960 d->d2 = 0;
5961 }
5962 else
5963 used = D_O_K;
5964
5965 /* if we changed something, better redraw... */
5966 if(d->d2 != start)
5967 {
5968 d->proc(MSG_DRAW, d, 0);
5969 }
5970
5971 ret = used;
5972 break;
5973
5974 case MSG_WANTFOCUS:
5975
5976 /* if we don't have a scrollbar we can't do anything with the focus */
5977 if(d->d1 > height)
5978 ret = D_WANTFOCUS;
5979
5980 break;
5981
5982 default:
5983 ret = D_O_K;
5984 }
5985
5986 if(d->dp2!=NULL)
5987 {
5988 font=oldfont;
5989 }
5990
5991 return ret;
5992 }
5993
5994 /* jwin_slider_proc:
5995 * A slider control object. This object returns a value in d2, in the
5996 * range from 0 to d1. It will display as a vertical slider if h is
5997 * greater than or equal to w; otherwise, it will display as a horizontal
5998 * slider. dp can contain an optional bitmap to use for the slider handle;
5999 * dp2 can contain an optional callback function, which is called each
6000 * time d2 changes. The callback function should have the following
6001 * prototype:
6002 *
6003 * int32_t function(void *dp3, int32_t d2);
6004 *
6005 * The d_slider_proc object will return the value of the callback function.
6006 */
6007 int32_t jwin_slider_proc(int32_t msg, DIALOG *d, int32_t c)
6008 {
6009 BITMAP *slhan = NULL;
6010 int32_t sfg; /* slider foreground color */
6011 int32_t vert = TRUE; /* flag: is slider vertical? */
6012 int32_t hh = 7; /* handle height (width for horizontal sliders) */
6013 int32_t hmar; /* handle margin */
6014 int32_t slp; /* slider position */
6015 int32_t irange;
6016 int32_t slx, sly, slh, slw;
6017 fixed slratio, slmax, slpos;
6018 ASSERT(d);
6019
6020 /* check for slider direction */
6021 if(d->h < d->w)
6022 {
6023 vert = FALSE;
6024 }
6025
6026 /* set up the metrics for the control */
6027 if(d->dp != NULL)
6028 {
6029 slhan = (BITMAP *)d->dp;
6030
6031 if(vert)
6032 {
6033 hh = slhan->h;
6034 }
6035 else
6036 {
6037 hh = slhan->w;
6038 }
6039 }
6040
6041 hmar = hh/2;
6042 irange = (vert) ? d->h : d->w;
6043 slmax = itofix(irange-hh);
6044 slratio = slmax / (d->d1);
6045 slpos = slratio * d->d2;
6046 slp = fixtoi(slpos);
6047
6048 switch(msg)
6049 {
6050 case MSG_DRAW:
6051 // sfg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : scheme[jcBOXFG];
6052 sfg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : scheme[jcBOXFG];
6053
6054 if(vert)
6055 {
6056 rectfill(screen, d->x, d->y, d->x+d->w/2-2, d->y+d->h, scheme[jcBOX]);
6057 rectfill(screen, d->x+d->w/2-1, d->y, d->x+d->w/2+1, d->y+d->h, sfg);
6058 rectfill(screen, d->x+d->w/2+2, d->y, d->x+d->w, d->y+d->h, scheme[jcBOX]);
6059 }
6060 else
6061 {
6062 rectfill(screen, d->x, d->y, d->x+d->w, d->y+d->h/2-2, scheme[jcBOX]);
6063 rectfill(screen, d->x, d->y+d->h/2-1, d->x+d->w, d->y+d->h/2+1, sfg);
6064 rectfill(screen, d->x, d->y+d->h/2+2, d->x+d->w, d->y+d->h, scheme[jcBOX]);
6065 }
6066
6067 if(d->flags & D_GOTFOCUS)
6068 {
6069 _dotted_rect(d->x, d->y, d->x+d->w, d->y+d->h, sfg, scheme[jcBOX]);
6070 }
6071
6072 /* okay, background and slot are drawn, now draw the handle */
6073 if(slhan)
6074 {
6075 if(vert)
6076 {
6077 slx = d->x+(d->w/2)-(slhan->w/2);
6078 sly = d->y+d->h-(hh+slp);
6079 }
6080 else
6081 {
6082 slx = d->x+slp;
6083 sly = d->y+(d->h/2)-(slhan->h/2);
6084 }
6085
6086 draw_sprite(screen, slhan, slx, sly);
6087 }
6088 else
6089 {
6090 /* draw default handle */
6091 if(vert)
6092 {
6093 slx = d->x;
6094 sly = d->y+d->h-(hh+slp);
6095 slw = d->w;
6096 slh = hh;
6097 }
6098 else
6099 {
6100 slx = d->x+slp;
6101 sly = d->y;
6102 slw = hh;
6103 slh = d->h;
6104 }
6105
6106 jwin_draw_button(screen, slx, sly, slw+1, slh+1, d->flags&D_DISABLED?3:0, 0);
6107 }
6108
6109 break;
6110
6111 default:
6112 return d_jslider_proc(msg, d, c);
6113 }
6114
6115 return D_O_K;
6116 }
6117
6118 const char* rowpref(int32_t row, bool alt)
6119 {
6120 static const char *lcol = "Level Colors", *syscol = "System Colors", *bosscol = "Boss Colors", *thmcol = "Theme Colors", *nlcol="";
6121 switch(row)
6122 {
6123 case 2: case 3: case 4: case 9:
6124 return lcol;
6125 case 14:
6126 return alt ? syscol : bosscol;
6127 case 15:
6128 return thmcol;
6129 default:
6130 return nlcol;
6131 }
6132 }
6133
6134 byte getHighlightColor(int32_t c)
6135 {
6136 RGB col;
6137 get_color(c, &col);
6138 return getHighlightColor(col);
6139 }
6140
6141 byte getHighlightColor(RGB const& col)
6142 {
6143 double lum = (pow(col.r/64.0, 2.2) * 0.2126) +
6144 (pow(col.g/64.0, 2.2) * 0.7152) +
6145 (pow(col.b/64.0, 2.2) * 0.0722);
6146 return lum < 0.4 ? vc(15) : vc(0);
6147 //Old -Em
6148 // byte bright = (col.r >= 32) + (col.g >= 32) + (col.b >= 32);
6149 // byte sbright = (col.r >= 48) + (col.g >= 48) + (col.b >= 48);
6150 // byte highlightColor = vc(7); //sysgray
6151 // if(bright >= 2)
6152 // {
6153 // if(sbright >= 2)
6154 // highlightColor = vc(0); //sysblack
6155 // else highlightColor = vc(8); //sysdarkgray
6156 // }
6157 // else if(!bright)
6158 // highlightColor = vc(15); //syswhite
6159 // return highlightColor;
6160 }
6161
6162 int32_t jwin_selcolor_proc(int32_t msg, DIALOG *d, int32_t c)
6163 {
6164 int32_t ret = D_O_K;
6165 if(!d->d2) d->d2 = 12;
6166 bool alt = d->d2 > 16;
6167 int32_t numcsets = alt ? 16 : d->d2;
6168 int32_t numcol = numcsets*0x10;
6169 if(msg==MSG_START)
6170 {
6171 d->w = d->h = (16*8) * 1.5;
6172 }
6173 int32_t csz = 12;
6174 d->w = csz * 16;
6175 d->h = csz * numcsets;
6176 switch(msg)
6177 {
6178 case MSG_DRAW:
6179 {
6180 jwin_draw_frame(screen, d->x-2, d->y-2, d->w+4, d->h+4, FR_ETCHED);
6181 for(int32_t c = 0; c < numcol; ++c)
6182 {
6183 int32_t x = (c%16)*csz, y = (c/16)*csz;
6184 rectfill(screen, d->x+x, d->y+y, d->x+x+csz-1, d->y+y+csz-1, c);
6185 if(c == d->d1)
6186 {
6187 byte highlightColor = getHighlightColor(c);
6188 rect(screen, d->x+x+0, d->y+y+0, d->x+x+csz-1, d->y+y+csz-1, highlightColor);
6189 rect(screen, d->x+x+1, d->y+y+1, d->x+x+csz-2, d->y+y+csz-2, highlightColor);
6190 }
6191 }
6192
6193 FONT *oldfont = font;
6194
6195 if(d->dp2)
6196 {
6197 font = (FONT*)d->dp2;
6198 }
6199
6200 char buf[32]={0};
6201 for(int32_t col = 0; col < 16; ++col)
6202 {
6203 sprintf(buf, "%X", col);
6204 gui_textout_ln(screen, (uint8_t*)buf, d->x + (csz*col) + (csz/2), d->y-3-text_height(font), scheme[jcBOXFG], scheme[jcBOX], 1);
6205 }
6206 for(int32_t row = 0; row < numcsets; ++row)
6207 {
6208 sprintf(buf, "%s 0x%02X", rowpref(row, alt), row*16);
6209 gui_textout_ln(screen, (uint8_t*)buf, d->x-3, d->y + (csz*row) + (csz-text_height(font))/2, scheme[jcBOXFG], scheme[jcBOX], 2);
6210 }
6211
6212 font = oldfont;
6213 break;
6214 }
6215
6216 case MSG_CLICK:
6217 {
6218 if(mouse_in_rect(d->x, d->y, d->x+d->w-1, d->y+d->h-1))
6219 {
6220 int32_t col = ((gui_mouse_x() - d->x) / csz) + 16*((gui_mouse_y() - d->y) / csz);
6221
6222 if(col>-1 && col != d->d1)
6223 {
6224 d->d1 = col;
6225 ret |= D_REDRAWME;
6226 }
6227 ret |= D_WANTFOCUS;
6228 }
6229 break;
6230 }
6231
6232 case MSG_WANTFOCUS:
6233 case MSG_LOSTFOCUS:
6234 case MSG_KEY:
6235 ret = D_WANTFOCUS;
6236 break;
6237
6238 case MSG_CHAR:
6239 {
6240 ret = D_USED_CHAR | D_REDRAWME;
6241 switch(c>>8)
6242 {
6243 case KEY_LEFT:
6244 {
6245 if(d->d1 % 0x10)
6246 --d->d1;
6247 break;
6248 }
6249 case KEY_RIGHT:
6250 {
6251 if(d->d1 % 0x10 != 0x0F)
6252 ++d->d1;
6253 break;
6254 }
6255 case KEY_UP:
6256 {
6257 if(d->d1 / 0x10)
6258 d->d1 -= 0x10;
6259 break;
6260 }
6261 case KEY_DOWN:
6262 {
6263 if(d->d1 / 0x10 != numcsets)
6264 d->d1 += 0x10;
6265 break;
6266 }
6267 case KEY_ENTER:
6268 {
6269 ret = D_CLOSE;
6270 break;
6271 }
6272 default: ret = D_O_K;
6273 }
6274 break;
6275 }
6276 }
6277 return ret;
6278 }
6279
6280 static DIALOG selcolor_dlg[] =
6281 {
6282 { jwin_win_proc, 0, 0, 306, 63+16*8, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *)"Select Color", NULL, NULL },
6283 { jwin_button_proc, 75, 40+16*8, 61, 21, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *)"OK", NULL, NULL },
6284 { jwin_button_proc, 164, 40+16*8, 61, 21, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *)"Cancel", NULL, NULL },
6285 { jwin_selcolor_proc, 156-64, 34, 16*8, 16*8, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6286
6287 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6288 };
6289
6290 int32_t jwin_color_swatch(int32_t msg, DIALOG *d, int32_t c)
6291 {
6292 int32_t ret = D_O_K;
6293
6294 switch(msg)
6295 {
6296 case MSG_START:
6297 {
6298 if(d->d2 < 1) d->d2 = 12;
6299 else if(d->d2 > 17) d->d2 = 17;
6300 break;
6301 }
6302
6303 case MSG_DRAW:
6304 {
6305 if(!d->d1 || (d->flags&D_DISABLED))
6306 {
6307 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1,
6308 (d->flags&D_DISABLED) ? scheme[jcDISABLED_BG] : vc(0));
6309 line(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1, vc(15));
6310 line(screen, d->x, d->y+d->h-1, d->x+d->w-1, d->y, vc(15));
6311 jwin_draw_frame(screen, d->x-2, d->y-2, d->w+4, d->h+4, FR_DEEP);
6312 }
6313 else
6314 {
6315 int32_t c;
6316 switch(d->d1) //special cases
6317 {
6318 case BLACK:
6319 c = vc(0);
6320 break;
6321 case WHITE:
6322 c = vc(15);
6323 break;
6324 default:
6325 c = d->d1;
6326 break;
6327 }
6328 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1, c);
6329 jwin_draw_frame(screen, d->x-2, d->y-2, d->w+4, d->h+4, FR_ETCHED);
6330 }
6331 break;
6332 }
6333
6334 case MSG_CLICK:
6335 {
6336 if(d->flags&(D_READONLY|D_DISABLED)) break;
6337 selcolor_dlg[0].dp2 = get_zc_font(font_lfont);
6338 selcolor_dlg[3].bg = scheme[jcBOXFG];
6339 selcolor_dlg[3].fg = scheme[jcBOX];
6340 selcolor_dlg[3].d1 = d->d1;
6341 selcolor_dlg[3].d2 = d->d2;
6342 large_dialog(selcolor_dlg);
6343
6344 while(gui_mouse_b()) rest(1); //wait for mouseup
6345
6346 //!TODO Move this out of jwin, and do better palette management.
6347 //!TODO Allow loading different level palettes, sprite palettes, etc via buttons
6348 PALETTE oldpal;
6349 get_palette(oldpal);
6350 bool alt = d->d2 > 16;
6351 if(!alt)
6352 {
6353 PALETTE foopal;
6354 get_palette(foopal);
6355 foopal[BLACK] = _RGB(0,0,0);
6356 foopal[WHITE] = _RGB(255,255,255);
6357 zc_set_palette(foopal);
6358 }
6359
6360 jwin_center_dialog(selcolor_dlg);
6361 int32_t val = do_zqdialog(selcolor_dlg, 3);
6362 ret = D_REDRAW;
6363
6364 zc_set_palette(oldpal);
6365 if(val == 1 || val == 3)
6366 {
6367 d->d1 = selcolor_dlg[3].d1;
6368 GUI_EVENT(d, geCHANGE_VALUE);
6369 ret |= D_REDRAWME;
6370 }
6371 if(d->flags & D_EXIT)
6372 return D_CLOSE;
6373 break;
6374 }
6375 }
6376 return ret;
6377 }
6378
6379 static DIALOG alert_dialog[] =
6380 {
6381 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
6382 { jwin_win_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6383 { d_ctext2_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6384 { d_ctext2_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6385 { d_ctext2_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6386 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6387 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6388 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6389 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6390 };
6391
6392 #define A_S1 1
6393 #define A_S2 2
6394 #define A_S3 3
6395 #define A_B1 4
6396 #define A_B2 5
6397 #define A_B3 6
6398
6399 /* jwin_alert3:
6400 * Displays a simple alert box, containing three lines of text (s1-s3),
6401 * and with either one, two, or three buttons. The text for these buttons
6402 * is passed in b1, b2, and b3 (NULL for buttons which are not used), and
6403 * the keyboard shortcuts in c1 and c2. Returns 1, 2, or 3 depending on
6404 * which button was selected.
6405 */
6406 int32_t jwin_alert3(const char *title, const char *s1, const char *s2, const char *s3, const char *b1, const char *b2, const char *b3, int32_t c1, int32_t c2, int32_t c3, FONT *title_font)
6407 {
6408 int32_t maxlen = 0;
6409 int32_t len1, len2, len3;
6410 int32_t avg_w = text_length(font, " ");
6411 int32_t avg_h = text_height(font)+1;
6412 int32_t buttons = 0;
6413 int32_t yofs = (title ? 22 : 0);
6414 int32_t b[3];
6415 int32_t c;
6416
6417 #define SORT_OUT_BUTTON(x) { \
6418 if (b##x) \
6419 { \
6420 alert_dialog[A_B##x].flags &= ~D_HIDDEN; \
6421 alert_dialog[A_B##x].key = c##x; \
6422 alert_dialog[A_B##x].dp = (void *)b##x; \
6423 len##x = gui_strlen(b##x); \
6424 b[buttons++] = A_B##x; \
6425 } \
6426 else \
6427 { \
6428 alert_dialog[A_B##x].flags |= D_HIDDEN; \
6429 len##x = 0; \
6430 } \
6431 }
6432
6433 if(title_font)
6434 {
6435 alert_dialog[0].dp2=title_font;
6436 }
6437
6438 alert_dialog[A_S1].dp = alert_dialog[A_S2].dp = alert_dialog[A_S3].dp =
6439 alert_dialog[A_B1].dp = alert_dialog[A_B2].dp = (void*)"";
6440
6441 if(s1)
6442 {
6443 alert_dialog[A_S1].dp = (void *)s1;
6444 maxlen = text_length(font, s1);
6445 }
6446
6447 if(s2)
6448 {
6449 alert_dialog[A_S2].dp = (void *)s2;
6450 len1 = text_length(font, s2);
6451
6452 if(len1 > maxlen)
6453 maxlen = len1;
6454 }
6455
6456 if(s3)
6457 {
6458 alert_dialog[A_S3].dp = (void *)s3;
6459 len1 = text_length(font, s3);
6460
6461 if(len1 > maxlen)
6462 maxlen = len1;
6463 }
6464
6465 SORT_OUT_BUTTON(1);
6466 SORT_OUT_BUTTON(2);
6467 SORT_OUT_BUTTON(3);
6468
6469 len1 = MAX(len1, MAX(len2, len3)) + avg_w*3;
6470
6471 if(len1*buttons > maxlen)
6472 maxlen = len1*buttons;
6473
6474 maxlen += avg_w*4;
6475 maxlen=zc_max(text_length(title_font?title_font:font,title)+29,maxlen);
6476 alert_dialog[0].w = maxlen;
6477 alert_dialog[A_S1].x = alert_dialog[A_S2].x = alert_dialog[A_S3].x =
6478 alert_dialog[0].x + maxlen/2;
6479
6480 alert_dialog[A_B1].w = alert_dialog[A_B2].w = alert_dialog[A_B3].w = len1;
6481
6482 alert_dialog[A_B1].x = alert_dialog[A_B2].x = alert_dialog[A_B3].x =
6483 alert_dialog[0].x + maxlen/2 - len1/2;
6484
6485 if(buttons == 3)
6486 {
6487 alert_dialog[b[0]].x = alert_dialog[0].x + maxlen/2 - len1*3/2 - avg_w;
6488 alert_dialog[b[2]].x = alert_dialog[0].x + maxlen/2 + len1/2 + avg_w;
6489 }
6490 else if(buttons == 2)
6491 {
6492 alert_dialog[b[0]].x = alert_dialog[0].x + maxlen/2 - len1 - avg_w;
6493 alert_dialog[b[1]].x = alert_dialog[0].x + maxlen/2 + avg_w;
6494 }
6495
6496 alert_dialog[0].h = avg_h*7 + 13 + yofs;
6497 alert_dialog[A_S1].y = alert_dialog[0].y + avg_h + yofs;
6498 alert_dialog[A_S2].y = alert_dialog[0].y + avg_h*2 + yofs;
6499 alert_dialog[A_S3].y = alert_dialog[0].y + avg_h*3 + yofs;
6500 alert_dialog[A_S1].h = alert_dialog[A_S2].h = alert_dialog[A_S3].h = avg_h;
6501
6502 alert_dialog[A_B1].y = alert_dialog[A_B2].y = alert_dialog[A_B3].y =
6503 alert_dialog[0].y + avg_h*5 + yofs;
6504
6505 alert_dialog[A_B1].h = alert_dialog[A_B2].h = alert_dialog[A_B3].h = avg_h+13;
6506
6507 alert_dialog[0].dp = (void *)title;
6508 alert_dialog[0].flags = (title) ? D_EXIT : 0;
6509
6510 jwin_center_dialog(alert_dialog);
6511 set_dialog_color(alert_dialog, scheme[jcTEXTFG], scheme[jcBOX]);
6512
6513 clear_keybuf();
6514
6515 do
6516 {
6517 rest(1);
6518 }
6519 while(gui_mouse_b());
6520
6521 large_dialog(alert_dialog);
6522 alert_dialog[0].d1 = 0;
6523
6524 c = do_zqdialog(alert_dialog, A_B1);
6525
6526 if(c == A_B1)
6527 return 1;
6528 else if(c == A_B2)
6529 return 2;
6530 else
6531 return 3;
6532 }
6533
6534 /* jwin_alert:
6535 * Displays a simple alert box, containing three lines of text (s1-s3),
6536 * and with either one or two buttons. The text for these buttons is passed
6537 * in b1 and b2 (b2 may be null), and the keyboard shortcuts in c1 and c2.
6538 * Returns 1 or 2 depending on which button was selected.
6539 */
6540 int32_t jwin_alert(const char *title, const char *s1, const char *s2, const char *s3, const char *b1, const char *b2, int32_t c1, int32_t c2, FONT *title_font)
6541 {
6542 int32_t ret;
6543
6544 ret = jwin_alert3(title, s1, s2, s3, b1, b2, NULL, c1, c2, 0, title_font);
6545
6546 if(ret > 2)
6547 ret = 2;
6548
6549 return ret;
6550 }
6551
6552 int32_t d_autotext_proc(int32_t msg, DIALOG *d, int32_t c)
6553 {
6554 ASSERT(d);
6555 ASSERT(d->dp);
6556 #define AUTOBUF_SIZE 8092
6557 static char auto_buf[AUTOBUF_SIZE] = {0};
6558 static int32_t auto_inds[50] = {0};
6559
6560
6561 FONT *oldfont = font;
6562
6563 if (d->dp2)
6564 font = (FONT*)d->dp2;
6565 switch(msg)
6566 {
6567 case MSG_START:
6568 {
6569 memset(auto_buf, 0, AUTOBUF_SIZE);
6570 memset(auto_inds, 0, 50);
6571 char* str = (char*)d->dp;
6572 int32_t len = strlen(str);
6573 int32_t pos = 0, curstrpos = 0, linecount = 1, lastWS = -1;
6574 BITMAP* dummy = create_bitmap_ex(8,8,8);
6575 for(int32_t q = 0; q < len; ++q)
6576 {
6577 switch(str[q])
6578 {
6579 case ' ': case '\t':
6580 lastWS = pos;
6581 break;
6582 case '\n': //Forced newline
6583 auto_inds[linecount++] = ++pos;
6584 curstrpos = pos;
6585 lastWS = -1;
6586 continue; //skip rest of for loop, go to next char
6587 }
6588 auto_buf[pos++] = str[q];
6589 if(gui_textout_ex(dummy,auto_buf+curstrpos,0,0,0,0,0) >= d->w) //too int32_t, wrap to lower line
6590 {
6591 if(lastWS<0)
6592 {
6593 auto_buf[pos-1] = 0;
6594 auto_inds[linecount++] = pos;
6595 curstrpos = pos;
6596 auto_buf[pos++] = str[q];
6597 }
6598 else
6599 {
6600 auto_buf[lastWS] = 0;
6601 auto_inds[linecount++] = lastWS+1;
6602 curstrpos = lastWS+1;
6603 if(gui_textout_ex(dummy,auto_buf+curstrpos,0,0,0,0,0) >= d->w) //STILL too int32_t?
6604 {
6605 auto_buf[pos-1] = 0;
6606 auto_inds[linecount++] = pos;
6607 curstrpos = pos;
6608 auto_buf[pos++] = str[q];
6609 }
6610 lastWS = -1;
6611 }
6612 }
6613 }
6614 destroy_bitmap(dummy);
6615 d->d2 = linecount;
6616 d->h = ((text_height(font) + d->d1) * linecount) - d->d1;
6617 }
6618 break;
6619
6620 case MSG_DRAW:
6621 {
6622 int32_t fg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
6623 int32_t linecount = d->d2;
6624
6625 int32_t yinc = text_height(font)+d->d1;
6626 int32_t y = d->y;
6627 for(int32_t q = 0; q < linecount; ++q)
6628 {
6629 gui_textout_ex(screen, auto_buf+auto_inds[q], d->x, y, fg, d->bg, true);
6630 y += yinc;
6631 }
6632 }
6633 break;
6634 }
6635 font = oldfont;
6636 return D_O_K;
6637 }
6638
6639 static DIALOG alert2_dialog[] =
6640 {
6641 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
6642 { jwin_win_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6643 { d_autotext_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6644 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6645 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6646 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6647 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6648 };
6649
6650 #define A2_S1 1
6651 #define A2_B1 2
6652 #define A2_B2 3
6653 #define A2_B3 4
6654
6655 /* jwin_auto_alert3:
6656 * Displays a simple alert box, containing one line of text, auto-split
6657 * across lines using 'lenlim' and 'vspace,
6658 * and with either one, two, or three buttons. The text for these buttons
6659 * is passed in b1, b2, and b3 (NULL for buttons which are not used), and
6660 * the keyboard shortcuts in c1 and c2. Returns 1, 2, or 3 depending on
6661 * which button was selected.
6662 */
6663 int32_t jwin_auto_alert3(const char *title, const char *s1, int32_t lenlim, int32_t vspace, const char *b1, const char *b2, const char *b3, int32_t c1, int32_t c2, int32_t c3, FONT *title_font)
6664 {
6665 int32_t maxlen = 0;
6666 int32_t len1, len2, len3;
6667 int32_t avg_w = text_length(font, " ");
6668 int32_t avg_h = text_height(font)+1;
6669 int32_t buttons = 0;
6670 int32_t yofs = (title ? 22 : 0);
6671 int32_t b[3];
6672 int32_t c;
6673
6674 #define SORT_OUT_AUTOBUTTON(x) { \
6675 if (b##x) \
6676 { \
6677 alert2_dialog[A2_B##x].flags &= ~D_HIDDEN; \
6678 alert2_dialog[A2_B##x].key = c##x; \
6679 alert2_dialog[A2_B##x].dp = (void *)b##x; \
6680 len##x = gui_strlen(b##x); \
6681 b[buttons++] = A2_B##x; \
6682 } \
6683 else \
6684 { \
6685 alert2_dialog[A2_B##x].flags |= D_HIDDEN; \
6686 len##x = 0; \
6687 } \
6688 }
6689
6690 if(title_font)
6691 {
6692 alert2_dialog[0].dp2=title_font;
6693 }
6694
6695 alert2_dialog[A2_S1].dp = alert2_dialog[A2_B1].dp = alert2_dialog[A2_B2].dp = (void*)"";
6696
6697 if(s1)
6698 {
6699 alert2_dialog[A2_S1].dp = (void *)s1;
6700 maxlen = lenlim;
6701 }
6702
6703 SORT_OUT_AUTOBUTTON(1);
6704 SORT_OUT_AUTOBUTTON(2);
6705 SORT_OUT_AUTOBUTTON(3);
6706
6707 len1 = MAX(len1, MAX(len2, len3)) + avg_w*3;
6708
6709 if(len1*buttons > maxlen)
6710 maxlen = len1*buttons;
6711
6712 maxlen += avg_w*4;
6713 maxlen=zc_max(text_length(title_font?title_font:font,title)+29,maxlen);
6714
6715 alert2_dialog[A2_S1].x = alert2_dialog[0].x + maxlen/2;
6716 alert2_dialog[A2_S1].y = alert2_dialog[0].y + avg_h + yofs;
6717 alert2_dialog[A2_S1].w = lenlim;
6718 alert2_dialog[A2_S1].d1 = vspace;
6719
6720 large_dialog(alert2_dialog);
6721 alert2_dialog[0].d1 = 0;
6722
6723 object_message(&alert2_dialog[A2_S1], MSG_START, 0); //calculate height
6724
6725 alert2_dialog[A2_S1].x = alert2_dialog[0].x + maxlen/2;
6726 alert2_dialog[A2_S1].y = alert2_dialog[0].y + avg_h + yofs;
6727 alert2_dialog[A2_S1].w = lenlim;
6728 alert2_dialog[A2_S1].d1 = vspace;
6729
6730 alert2_dialog[A2_B1].w = alert2_dialog[A2_B2].w = alert2_dialog[A2_B3].w = len1;
6731
6732 alert2_dialog[A2_B1].x = alert2_dialog[A2_B2].x = alert2_dialog[A2_B3].x =
6733 alert2_dialog[0].x + maxlen/2 - len1/2;
6734
6735 if(buttons == 3)
6736 {
6737 alert2_dialog[b[0]].x = alert2_dialog[0].x + maxlen/2 - len1*3/2 - avg_w;
6738 alert2_dialog[b[2]].x = alert2_dialog[0].x + maxlen/2 + len1/2 + avg_w;
6739 }
6740 else if(buttons == 2)
6741 {
6742 alert2_dialog[b[0]].x = alert2_dialog[0].x + maxlen/2 - len1 - avg_w;
6743 alert2_dialog[b[1]].x = alert2_dialog[0].x + maxlen/2 + avg_w;
6744 }
6745
6746 alert2_dialog[0].w = maxlen;
6747 alert2_dialog[0].h = avg_h*4 + yofs + alert2_dialog[A2_S1].h + 13;
6748 alert2_dialog[A2_B1].y = alert2_dialog[A2_B2].y = alert2_dialog[A2_B3].y =
6749 alert2_dialog[0].y + avg_h*2 + yofs + alert2_dialog[A2_S1].h;
6750
6751 alert2_dialog[A2_B1].h = alert2_dialog[A2_B2].h = alert2_dialog[A2_B3].h = avg_h+13;
6752
6753 alert2_dialog[0].dp = (void *)title;
6754 alert2_dialog[0].flags = (title) ? D_EXIT : 0;
6755
6756 jwin_center_dialog(alert2_dialog);
6757 set_dialog_color(alert2_dialog, scheme[jcTEXTFG], scheme[jcBOX]);
6758
6759 clear_keybuf();
6760
6761 do
6762 {
6763 rest(1);
6764 }
6765 while(gui_mouse_b());
6766
6767 large_dialog(alert2_dialog);
6768 alert2_dialog[0].d1 = 0;
6769
6770 c = do_zqdialog(alert2_dialog, A2_B1);
6771
6772 if(c == A2_B1)
6773 return 1;
6774 else if(c == A2_B2)
6775 return 2;
6776 else
6777 return 3;
6778 }
6779
6780 int32_t jwin_auto_alert(const char *title, const char *s1, int32_t lenlim, int32_t vspace, const char *b1, const char *b2, int32_t c1, int32_t c2, FONT *title_font)
6781 {
6782 int32_t ret;
6783
6784 ret = jwin_auto_alert3(title, s1, lenlim, vspace, b1, b2, NULL, c1, c2, 0, title_font);
6785
6786 if(ret > 2)
6787 ret = 2;
6788
6789 return ret;
6790 }
6791
6792 int32_t last_droplist_sel = -1;
6793 static int32_t d_dropcancel_proc(int32_t msg,DIALOG *d,int32_t c)
6794 {
6795 //these are here to bypass compiler warnings about unused arguments
6796 d=d;
6797 c=c;
6798
6799 if(msg==MSG_CLICK || msg==MSG_DCLICK)
6800 return D_CLOSE;
6801
6802 return D_O_K;
6803 }
6804
6805 static DIALOG droplist_dlg[] =
6806 {
6807 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3)*/
6808 { d_dropcancel_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6809 { d_list_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6810 { d_keyboard_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_ESC, (void*)close_dlg, NULL, NULL },
6811 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6812 };
6813
6814 static int32_t droplist(DIALOG *d)
6815 {
6816 ListData *data = (ListData *)d->dp;
6817 int32_t d1 = d->d1;
6818 int32_t listsize, x, y, w, h, max_w;
6819 auto oz = gui_mouse_z();
6820
6821 data->listFunc(-1, &listsize);
6822 y = d->y + d->h;
6823 h = zc_min(abc_patternmatch ? listsize+1 : listsize,8) * text_height(*data->font) + 8;
6824
6825 if(y+h >= zq_screen_h)
6826 {
6827 y = d->y - h;
6828 }
6829
6830 x = d->x;
6831 w = d->w;
6832 max_w = zc_max(d->x+d->w, zq_screen_w-d->x);
6833
6834 for(int32_t i=0; i<listsize; ++i)
6835 {
6836 w=zc_min(max_w,zc_max(w,text_length(*data->font,data->listFunc(i, NULL))+39));
6837 }
6838
6839 if(x+w >= zq_screen_w)
6840 {
6841 x=zq_screen_w-w;
6842 }
6843
6844 droplist_dlg[1] = *d;
6845 droplist_dlg[1].proc = &jwin_abclist_proc;
6846 droplist_dlg[1].flags = D_EXIT + D_USER;
6847 droplist_dlg[1].x = x;
6848 droplist_dlg[1].y = y;
6849 droplist_dlg[1].w = w;
6850 droplist_dlg[1].h = h;
6851 droplist_dlg[1].d2 = listsize<=8 ? 0 : zc_max(d1-3,0);
6852
6853 // cancel
6854 droplist_dlg[0].x = 0;
6855 droplist_dlg[0].y = 0;
6856 droplist_dlg[0].w = zq_screen_w;
6857 droplist_dlg[0].h = zq_screen_h;
6858
6859 if(do_zq_subdialog(droplist_dlg,1)==1)
6860 {
6861 position_mouse_z(oz);
6862 return droplist_dlg[1].d1;
6863 }
6864
6865 position_mouse_z(oz);
6866 return d1;
6867 }
6868
6869 /* jwin_droplist_proc:
6870 * A drop list...
6871 */
6872 int32_t jwin_droplist_proc(int32_t msg,DIALOG *d,int32_t c)
6873 {
6874 int32_t ret;
6875 int32_t down=0, last_draw=0;
6876 int32_t d1;
6877
6878 switch(msg)
6879 {
6880 case MSG_CLICK:
6881 if(mouse_in_rect(d->x+d->w-18,d->y+2,16,d->h))
6882 goto dropit;
6883
6884 break;
6885
6886 case MSG_KEY:
6887 goto dropit;
6888 break;
6889 }
6890
6891 d1 = d->d1;
6892 ret = jwin_list_proc(msg,d,c);
6893
6894 if(d->d1!=d->d2)
6895 {
6896 d->d1=d->d2;
6897 jwin_droplist_proc(MSG_DRAW, d, 0);
6898 }
6899
6900 if(d1 != d->d1)
6901 {
6902 GUI_EVENT(d, geCHANGE_SELECTION);
6903 if(d->flags&D_EXIT)
6904 ret |= D_CLOSE;
6905 }
6906
6907 if(msg == MSG_DRAW)
6908 {
6909 draw_arrow_button(screen, d->x+d->w-18, d->y+2,16, d->h-4, 0, 0);
6910 }
6911
6912 return ret;
6913
6914 dropit:
6915 last_draw = 0;
6916
6917 while(gui_mouse_b())
6918 {
6919 down = mouse_in_rect(d->x+d->w-18,d->y+2,16,d->h);
6920
6921 if(down!=last_draw)
6922 {
6923 draw_arrow_button(screen, d->x+d->w-18, d->y+2,16, d->h-4, 0, down*3);
6924 last_draw = down;
6925 update_hw_screen();
6926 }
6927
6928 clear_keybuf();
6929 rest(1);
6930 }
6931
6932 if(!down)
6933 {
6934 return D_O_K;
6935 }
6936
6937 draw_arrow_button(screen, d->x+d->w-18, d->y+2,16, d->h-4, 0, 0);
6938
6939 d1 = d->d1;
6940 d->d2 = d->d1 = droplist(d);
6941
6942 object_message(d, MSG_DRAW, 0);
6943
6944 while(gui_mouse_b())
6945 {
6946 clear_keybuf();
6947 rest(1);
6948 update_hw_screen();
6949 }
6950
6951 if(d1!=d->d1)
6952 GUI_EVENT(d, geCHANGE_SELECTION);
6953
6954 return ((d1 != d->d1) && (d->flags&D_EXIT)) ? D_CLOSE : D_O_K;
6955 }
6956
6957
6958 int32_t jwin_abclist_proc(int32_t msg,DIALOG *d,int32_t c)
6959 {
6960 ListData *data = (ListData *)d->dp;
6961 if(msg == MSG_START) wipe_abc_keypresses();
6962
6963 if(msg == MSG_CHAR && (key_shifts&KB_CTRL_CMD_FLAG))
6964 return D_O_K;
6965
6966 if(abc_patternmatch) // Search style pattern match.
6967 {
6968 if(msg==MSG_CHAR && ((c&0xFF) > 31) && ((c&0xFF) < 127)) //(isalpha(c&0xFF) || isdigit(c&0xFF)))
6969 {
6970 int32_t max,dummy,h;
6971
6972 h = ((d->h-3) / text_height(*data->font))-1;
6973 if ( isalpha(c&0xFF) ) c = toupper(c&0xFF);
6974 for ( int32_t q = 0; q < 1023; ++q )
6975 {
6976 if ( !(abc_keypresses[q]) )
6977 {
6978 abc_keypresses[q] = (char)c;
6979 break;
6980 }
6981 }
6982 data->listFunc(-1, &max);
6983
6984 int32_t cur = d->d1;
6985 int32_t charpos = 0; int32_t listpos = 0; int32_t lastmatch = -1;
6986 char tmp[1024] = { 0 };
6987 char lsttmp[1024] = { 0 };
6988 int32_t lastmatches[32768] = {0};
6989 for ( int32_t a = 0; a < 32768; ++a ) lastmatches[a] = -1;
6990 int32_t lmindx = 0;
6991
6992 bool foundmatch = false;
6993 bool numsearch = true;
6994 for ( int32_t q = 0; q < 1023; ++q )
6995 {
6996 if(!abc_keypresses[q]) break;
6997 if(!isdigit(abc_keypresses[q]))
6998 {
6999 if(q == 0 && abc_keypresses[q] == '-')
7000 continue;
7001 numsearch = false;
7002 break;
7003 }
7004 }
7005 if(numsearch) //Indexed search, first
7006 {
7007 int32_t num = atoi(abc_keypresses);
7008 //Find a different indexing type in the strings?
7009 if(!foundmatch)
7010 {
7011 char buf[16];
7012 if(num < 0) sprintf(buf, "(%04d)", num);
7013 else sprintf(buf, "(%03d)", num);
7014 std::string cmp = buf;
7015 for(int32_t listpos = 0; listpos < max; ++listpos)
7016 {
7017 std::string str((data->listFunc(listpos,&dummy)));
7018 size_t trimpos = str.find_last_not_of("-(0123456789)");
7019 if(trimpos != std::string::npos) ++trimpos;
7020 str.erase(0, trimpos);
7021 if(cmp == str)
7022 {
7023 d->d1 = listpos;
7024 d->d2 = zc_max(zc_min(listpos-(h>>1), max-h), 0);
7025 foundmatch = true;
7026 break;
7027 }
7028 }
7029 }
7030 //Search for match with first number in string?
7031 if(!foundmatch)
7032 {
7033 auto buf = fmt::format("{}", num);
7034 for(int32_t listpos = 0; listpos < max; ++listpos)
7035 {
7036 std::string str((data->listFunc(listpos,&dummy)));
7037 size_t pos1 = -1;
7038 do
7039 {
7040 pos1 = str.find_first_of("-0123456789", pos1+1);
7041 } while(pos1 != string::npos && str[pos1] == '-' && pos1+1 < str.size() && !isdigit(str[pos1+1]));
7042 if(pos1 == string::npos)
7043 continue;
7044 size_t pos2 = str.find_first_not_of("-0123456789", pos1);
7045 if(pos2 == string::npos)
7046 continue;
7047 str = str.substr(pos1,pos2-pos1);
7048 if(buf == str)
7049 {
7050 d->d1 = listpos;
7051 d->d2 = zc_max(zc_min(listpos-(h>>1), max-h), 0);
7052 foundmatch = true;
7053 break;
7054 }
7055 }
7056 }
7057 }
7058 if(!foundmatch)
7059 {
7060 strcpy(tmp, abc_keypresses);
7061 for ( int32_t listpos = 0; listpos < max; ++listpos )
7062 {
7063 memset(lsttmp, 0, 1024);
7064 strcpy(lsttmp, ((data->listFunc(listpos,&dummy))));
7065
7066 if ( !(strnicmp(lsttmp, tmp, strlen(tmp))))
7067 {
7068 d->d1 = listpos;
7069 d->d2 = zc_max(zc_min(listpos-(h>>1), max-h), 0);
7070 foundmatch = true;
7071 break;
7072 }
7073 }
7074 }
7075 if(foundmatch)
7076 GUI_EVENT(d, geCHANGE_SELECTION);
7077 d->flags |= D_DIRTY;
7078 if ( gui_mouse_b() ) wipe_abc_keypresses();
7079 return foundmatch ? D_USED_CHAR : D_O_K;
7080 }
7081 else if(msg==MSG_CHAR && ( (c&0xFF) == 8) )//backspace
7082 {
7083 for ( int32_t q = 1023; q >= 0; --q )
7084 {
7085 if ( abc_keypresses[q] )
7086 {
7087 d->flags |= D_DIRTY;
7088 abc_keypresses[q] = '\0'; break;
7089 }
7090 }
7091 return D_USED_CHAR;
7092 }
7093 if ( gui_mouse_b() ) { wipe_abc_keypresses(); }
7094 }
7095 else // Windows Explorer style jumping
7096 {
7097 if(msg==MSG_CHAR && (isalpha(c&0xFF) || isdigit(c&0xFF)))
7098 {
7099 int32_t max,dummy,h,i;
7100
7101 h = (d->h-3) / text_height(*data->font);
7102 c = toupper(c&0xFF);
7103
7104 data->listFunc(-1, &max);
7105
7106 int32_t cur = d->d1;
7107 bool foundmatch = false;
7108 for(i=cur+1; (cur ? (i != cur) : (cur < max)); ++i) //don't infinite loop this.
7109 {
7110 if(i>=max) i=0;
7111 if(toupper((data->listFunc(i,&dummy))[0]) == c)
7112 {
7113 d->d1 = i;
7114 d->d2 = zc_max(zc_min(i-(h>>1), max-h), 0);
7115 foundmatch = true;
7116 break;
7117 }
7118 }
7119
7120 d->flags |= D_DIRTY;
7121 return foundmatch ? D_USED_CHAR : D_O_K;
7122 }
7123 }
7124 if ( gui_mouse_b() ) { wipe_abc_keypresses(); }
7125 return ((abc_patternmatch) ? jwin_do_abclist_proc(msg,d,c) : jwin_list_proc(msg,d,c));
7126 }
7127
7128 int32_t jwin_checkfont_proc(int32_t msg, DIALOG *d, int32_t c)
7129 {
7130
7131 FONT *oldfont = font;
7132
7133 if(d->dp2)
7134 {
7135 font = (FONT *)d->dp2;
7136 }
7137
7138 int32_t rval = jwin_check_proc(msg, d, c);
7139 font = oldfont;
7140 return rval;
7141 }
7142
7143 /* jwin_check_proc:
7144 * Who needs C++ after all? This is derived from d_button_proc,
7145 * but overrides the drawing routine to provide a check box.
7146 */
7147 int32_t jwin_check_proc(int32_t msg, DIALOG *d, int32_t c)
7148 {
7149 //these are here to bypass compiler warnings about unused arguments
7150 c=c;
7151 int32_t x;
7152 int32_t bx=0, tl=0;
7153 int32_t tx=d->x;
7154 ASSERT(d);
7155
7156 switch(msg)
7157 {
7158 case MSG_DRAW:
7159 x = d->x;
7160
7161 if(!(d->d1))
7162 {
7163 if(d->dp)
7164 {
7165 if(d->flags & D_DISABLED)
7166 {
7167 gui_textout_ln(screen, (uint8_t *)d->dp, tx+1, d->y+1+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcLIGHT], scheme[jcBOX], 0);
7168 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcDISABLED_FG], -1, 0);
7169 bx=tl+text_height(font)/2;
7170 }
7171 else
7172 {
7173 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcBOXFG], scheme[jcBOX], 0);
7174 bx=tl+text_height(font)/2;
7175 }
7176 }
7177 }
7178
7179 jwin_draw_frame(screen, x+bx, d->y, d->h, d->h, FR_DEEP);
7180
7181 if(!(d->flags & D_DISABLED))
7182 {
7183 rectfill(screen, x+bx+2, d->y+2, x+bx+d->h-3, d->y+d->h-3, scheme[jcTEXTBG]);
7184 }
7185
7186 if(d->d1)
7187 {
7188 tx=x+bx+d->h-1+(text_height(font)/2);
7189
7190 if(d->dp)
7191 {
7192 if(d->flags & D_DISABLED)
7193 {
7194 gui_textout_ln(screen, (uint8_t *)d->dp, tx+1, d->y+1+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcLIGHT], scheme[jcBOX], 0);
7195 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcDISABLED_FG], -1, 0);
7196 }
7197 else
7198 {
7199 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcBOXFG], scheme[jcBOX], 0);
7200 }
7201 }
7202 }
7203
7204 if(d->flags & D_SELECTED)
7205 {
7206 line(screen, x+bx+2, d->y+2, x+bx+d->h-3, d->y+d->h-3, scheme[jcTEXTFG]);
7207 line(screen, x+bx+2, d->y+d->h-3, x+bx+d->h-3, d->y+2, scheme[jcTEXTFG]);
7208 }
7209
7210 d->w=int32_t(text_height(font)*1.5);
7211
7212 if(d->dp)
7213 {
7214 // dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+d->h-1, (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7215 dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+(text_height(font)), (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7216 d->w+=tl+1;
7217 }
7218
7219 return D_O_K;
7220 break;
7221 }
7222
7223 return d_jwinbutton_proc(msg, d, 0);
7224 }
7225
7226 int32_t jwin_radiofont_proc(int32_t msg, DIALOG *d, int32_t c)
7227 {
7228 FONT *oldfont = font;
7229
7230 if(d->dp2)
7231 {
7232 font = (FONT *)d->dp2;
7233 }
7234
7235 int32_t rval = jwin_radio_proc(msg, d, c);
7236 font = oldfont;
7237 return rval;
7238 }
7239
7240 /* jwin_radio_proc:
7241 * GUI procedure for radio buttons.
7242 * Parameters: d1-button group number; d2-button style (0=circle,1=square);
7243 * dp-text to appear as label to the right of the button.
7244 */
7245 int32_t jwin_radio_proc(int32_t msg, DIALOG *d, int32_t c)
7246 {
7247 int32_t x, center, r, ret, tl=0, tx;
7248 ASSERT(d);
7249
7250 switch(msg)
7251 {
7252 case MSG_DRAW:
7253 // tx=d->x+d->h-1+text_height(font);
7254 tx=d->x+int32_t(text_height(font)*1.5);
7255
7256 if(d->dp)
7257 {
7258 if(d->flags & D_DISABLED)
7259 {
7260 gui_textout_ln(screen, (uint8_t *)d->dp, tx+1, d->y+1+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcLIGHT], scheme[jcBOX], 0);
7261 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcDISABLED_FG], -1, 0);
7262 }
7263 else
7264 {
7265 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcBOXFG], scheme[jcBOX], 0);
7266 }
7267 }
7268
7269 x = d->x;
7270 r = d->h/2;
7271
7272 center = x+r;
7273 rectfill(screen, x, d->y, x+d->h-1, d->y+d->h-1, scheme[jcBOX]);
7274
7275 switch(d->d2)
7276 {
7277 case 1:
7278 jwin_draw_frame(screen, x, d->y, d->h, d->h, FR_DEEP);
7279
7280 if(!(d->flags & D_DISABLED))
7281 {
7282 rectfill(screen, x+2, d->y+2, x+d->h-3, d->y+d->h-3, scheme[jcLIGHT]);
7283 }
7284
7285 if(d->flags & D_SELECTED)
7286 {
7287 rectfill(screen, x+r/2, d->y+r/2, x+d->h-1-r/2, d->y+d->h-1-r/2, scheme[jcDARK]);
7288 //line(screen, x+2, d->y+2, x+d->h-3, d->y+d->h-3, scheme[jcDARK]);
7289 //line(screen, x+2, d->y+d->h-3, x+d->h-3, d->y+2, scheme[jcDARK]);
7290 }
7291
7292 break;
7293
7294 default:
7295 circlefill(screen, center, d->y+r, r, scheme[jcTEXTBG]);
7296 arc(screen, center, d->y+r, itofix(32), itofix(160), r, vc(0));
7297 circlefill(screen, center, d->y+r, r-1, scheme[jcTEXTBG]);
7298 arc(screen, center, d->y+r, itofix(32), itofix(160), r-1, vc(0));
7299 circlefill(screen, center, d->y+r, r-2, (d->flags & D_DISABLED)?scheme[jcDISABLED_BG]:scheme[jcTEXTBG]);
7300
7301 if(d->flags & D_SELECTED)
7302 {
7303 circlefill(screen, center, d->y+r, r-3, scheme[jcTEXTFG]);
7304 }
7305
7306 break;
7307 }
7308
7309 if(d->dp)
7310 {
7311 // dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+d->h-1, (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7312 dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+(text_height(font)), (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7313 d->w=tl+int32_t(text_height(font)*1.5)+1;
7314 }
7315
7316 return D_O_K;
7317
7318 case MSG_KEY:
7319 case MSG_CLICK:
7320 if(d->flags & D_SELECTED)
7321 {
7322 return D_O_K;
7323 }
7324
7325 break;
7326
7327 case MSG_RADIO:
7328 if((c == d->d1) && (d->flags & D_SELECTED))
7329 {
7330 d->flags &= ~D_SELECTED;
7331 object_message(d, MSG_DRAW, 0);
7332 }
7333
7334 break;
7335 }
7336
7337 ret = d_jwinbutton_proc(msg, d, 0);
7338
7339 if(((msg==MSG_KEY) || (msg==MSG_CLICK)) && (d->flags & D_SELECTED) && (!(d->flags & D_EXIT)))
7340 {
7341 d->flags &= ~D_SELECTED;
7342 broadcast_dialog_message(MSG_RADIO, d->d1);
7343 d->flags |= D_SELECTED;
7344 GUI_EVENT(d, geRADIO);
7345 }
7346
7347 return ret;
7348 }
7349
7350
7351 /* 1.5k lookup table for color matching */
7352 uint32_t col_diff[3*128];
7353
7354 /* bestfit_init:
7355 * Color matching is done with weighted squares, which are much faster
7356 * if we pregenerate a little lookup table...
7357 */
7358 11 void bestfit_init(void)
7359 {
7360 int32_t i;
7361
7362 11 col_diff[0] = col_diff[128] = col_diff[256] = 0;
7363
7364
2/2
✓ Branch 0 taken 693 times.
✓ Branch 1 taken 11 times.
704 for(i=1; i<64; i++)
7365 {
7366 693 int32_t k = i * i;
7367 693 col_diff[0 +i] = col_diff[0 +128-i] = k * (59 * 59);
7368 693 col_diff[128+i] = col_diff[128+128-i] = k * (30 * 30);
7369 693 col_diff[256+i] = col_diff[256+128-i] = k * (11 * 11);
7370 693 }
7371 11 }
7372
7373
7374
7375 /* bestfit_color:
7376 * Searches a palette for the color closest to the requested R, G, B value.
7377 */
7378 int32_t bestfit_color_range(AL_CONST PALETTE pal, int32_t r, int32_t g, int32_t b, uint8_t start, uint8_t end)
7379 {
7380 int32_t i, coldiff, lowest, bestfit;
7381
7382 if(col_diff[1] == 0)
7383 bestfit_init();
7384
7385 bestfit = start;
7386 lowest = INT_MAX;
7387
7388 i = start;
7389
7390 while(i<PAL_SIZE&&i<=end)
7391 {
7392 AL_CONST RGB *rgb = &pal[i];
7393 coldiff = (col_diff + 0) [(rgb->g - g) & 0x7F ];
7394
7395 if(coldiff < lowest)
7396 {
7397 coldiff += (col_diff + 128) [(rgb->r - r) & 0x7F ];
7398
7399 if(coldiff < lowest)
7400 {
7401 coldiff += (col_diff + 256) [(rgb->b - b) & 0x7F ];
7402
7403 if(coldiff < lowest)
7404 {
7405 bestfit = rgb - pal; /* faster than `bestfit = i;' */
7406
7407 if(coldiff == 0)
7408 {
7409 return bestfit;
7410 }
7411
7412 lowest = coldiff;
7413 }
7414 }
7415 }
7416
7417 i++;
7418 }
7419
7420 return bestfit;
7421 }
7422
7423
7424 /* makecol8:
7425 * Converts R, G, and B values (ranging 0-255) to an 8 bit paletted color.
7426 * If the global rgb_map table is initialised, it uses that, otherwise
7427 * it searches through the current palette to find the best match.
7428 */
7429 int32_t makecol8_map(int32_t r, int32_t g, int32_t b, RGB_MAP *table)
7430 {
7431 return table->data[r>>3][g>>3][b>>3];
7432 }
7433
7434
7435 /* create_rgb_table:
7436 * Fills an RGB_MAP lookup table with conversion data for the specified
7437 * palette. This is the faster version by Jan Hubicka.
7438 *
7439 * Uses alg. similar to floodfill - it adds one seed per every color in
7440 * palette to its best position. Then areas around seed are filled by
7441 * same color because it is best approximation for them, and then areas
7442 * about them etc...
7443 *
7444 * It does just about 80000 tests for distances and this is about 100
7445 * times better than normal 256*32000 tests so the calculation time
7446 * is now less than one second at all computers I tested.
7447 */
7448 void create_rgb_table_range(RGB_MAP *table, AL_CONST PALETTE pal_8bit, uint8_t start, uint8_t end, void (*callback)(int32_t pos))
7449 {
7450 #define UNUSED 65535
7451 #define LAST 65532
7452
7453 // Allegro has been modified to use an 8 bit palette, but this method and RGB_MAP still use 6 bit.
7454 PALETTE pal;
7455 for (int i = 0; i < 256; i++)
7456 {
7457 pal[i] = pal_8bit[i];
7458 pal[i].r /= 4;
7459 pal[i].g /= 4;
7460 pal[i].b /= 4;
7461 }
7462
7463 /* macro add adds to single linked list */
7464 #define add(i) (next[(i)] == UNUSED ? (next[(i)] = LAST, \
7465 (first != LAST ? (next[last] = (i)) : (first = (i))), \
7466 (last = (i))) : 0)
7467
7468 /* same but w/o checking for first element */
7469 #define add1(i) (next[(i)] == UNUSED ? (next[(i)] = LAST, \
7470 next[last] = (i), \
7471 (last = (i))) : 0)
7472
7473 /* calculates distance between two colors */
7474 #define dist(a1, a2, a3, b1, b2, b3) \
7475 (col_diff[ ((a2) - (b2)) & 0x7F] + \
7476 (col_diff + 128)[((a1) - (b1)) & 0x7F] + \
7477 (col_diff + 256)[((a3) - (b3)) & 0x7F])
7478
7479 /* converts r,g,b to position in array and back */
7480 #define pos(r, g, b) \
7481 (((r) / 2) * 32 * 32 + ((g) / 2) * 32 + ((b) / 2))
7482
7483 #define depos(pal, r, g, b) \
7484 ((b) = ((pal) & 31) * 2, \
7485 (g) = (((pal) >> 5) & 31) * 2, \
7486 (r) = (((pal) >> 10) & 31) * 2)
7487
7488 /* is current color better than pal1? */
7489 #define better(r1, g1, b1, pal1) \
7490 (((int32_t)dist((r1), (g1), (b1), \
7491 (pal1).r, (pal1).g, (pal1).b)) > (int32_t)dist2)
7492
7493 /* checking of position */
7494 #define dopos(rp, gp, bp, ts) \
7495 if ((rp > -1 || r > 0) && (rp < 1 || r < 61) && \
7496 (gp > -1 || g > 0) && (gp < 1 || g < 61) && \
7497 (bp > -1 || b > 0) && (bp < 1 || b < 61)) { \
7498 i = first + rp * 32 * 32 + gp * 32 + bp; \
7499 if (!data[i]) { \
7500 data[i] = val; \
7501 add1(i); \
7502 } \
7503 else if ((ts) && (data[i] != val)) { \
7504 dist2 = (rp ? (col_diff+128)[(r+2*rp-pal[val].r) & 0x7F] : r2) + \
7505 (gp ? (col_diff )[(g+2*gp-pal[val].g) & 0x7F] : g2) + \
7506 (bp ? (col_diff+256)[(b+2*bp-pal[val].b) & 0x7F] : b2); \
7507 if (better((r+2*rp), (g+2*gp), (b+2*bp), pal[data[i]])) { \
7508 data[i] = val; \
7509 add1(i); \
7510 } \
7511 } \
7512 }
7513
7514 int32_t i, curr, r, g, b, val, dist2;
7515 uint32_t r2, g2, b2;
7516 uint16_t next[32*32*32];
7517 uint8_t *data;
7518 int32_t first = LAST;
7519 int32_t last = LAST;
7520 int32_t count = 0;
7521 int32_t cbcount = 0;
7522
7523 #define AVERAGE_COUNT 18000
7524
7525 if(col_diff[1] == 0)
7526 bestfit_init();
7527
7528 memset(next, 255, sizeof(next));
7529 memset(table->data, 0, sizeof(char)*32*32*32);
7530
7531 data = (uint8_t *)table->data;
7532
7533 /* add starting seeds for floodfill */
7534 for(i=start; i<PAL_SIZE&&i<=end; i++)
7535 {
7536 curr = pos(pal[i].r, pal[i].g, pal[i].b);
7537
7538 if(next[curr] == UNUSED)
7539 {
7540 data[curr] = i;
7541 add(curr);
7542 }
7543 }
7544
7545 /* main floodfill: two versions of loop for faster growing in blue axis */
7546 while(first < LAST)
7547 {
7548 depos(first, r, g, b);
7549
7550 /* calculate distance of current color */
7551 val = data[first];
7552 r2 = (col_diff+128)[((pal[val].r)-(r)) & 0x7F];
7553 g2 = (col_diff)[((pal[val].g)-(g)) & 0x7F];
7554 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7F];
7555
7556 /* try to grow to all directions */
7557 #ifdef _MSC_VER
7558 #pragma warning(disable:4127)
7559 #endif
7560 dopos(0, 0, 1, 1);
7561 dopos(0, 0,-1, 1);
7562 dopos(1, 0, 0, 1);
7563 dopos(-1, 0, 0, 1);
7564 dopos(0, 1, 0, 1);
7565 dopos(0,-1, 0, 1);
7566 #ifdef _MSC_VER
7567 #pragma warning(default:4127)
7568 #endif
7569
7570 /* faster growing of blue direction */
7571 if((b > 0) && (data[first-1] == val))
7572 {
7573 b -= 2;
7574 first--;
7575 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7F];
7576
7577 #ifdef _MSC_VER
7578 #pragma warning(disable:4127)
7579 #endif
7580 dopos(-1, 0, 0, 0);
7581 dopos(1, 0, 0, 0);
7582 dopos(0,-1, 0, 0);
7583 dopos(0, 1, 0, 0);
7584 #ifdef _MSC_VER
7585 #pragma warning(default:4127)
7586 #endif
7587
7588 first++;
7589 }
7590
7591 /* get next from list */
7592 i = first;
7593 first = next[first];
7594 next[i] = UNUSED;
7595
7596 /* second version of loop */
7597 if(first != LAST)
7598 {
7599 depos(first, r, g, b);
7600
7601 val = data[first];
7602 r2 = (col_diff+128)[((pal[val].r)-(r)) & 0x7F];
7603 g2 = (col_diff)[((pal[val].g)-(g)) & 0x7F];
7604 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7F];
7605
7606 #ifdef _MSC_VER
7607 #pragma warning(disable:4127)
7608 #endif
7609 dopos(0, 0, 1, 1);
7610 dopos(0, 0,-1, 1);
7611 dopos(1, 0, 0, 1);
7612 dopos(-1, 0, 0, 1);
7613 dopos(0, 1, 0, 1);
7614 dopos(0,-1, 0, 1);
7615 #ifdef _MSC_VER
7616 #pragma warning(default:4127)
7617 #endif
7618
7619 if((b < 61) && (data[first + 1] == val))
7620 {
7621 b += 2;
7622 first++;
7623 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7f];
7624
7625 #ifdef _MSC_VER
7626 #pragma warning(disable:4127)
7627 #endif
7628 dopos(-1, 0, 0, 0);
7629 dopos(1, 0, 0, 0);
7630 dopos(0,-1, 0, 0);
7631 dopos(0, 1, 0, 0);
7632 #ifdef _MSC_VER
7633 #pragma warning(default:4127)
7634 #endif
7635
7636 first--;
7637 }
7638
7639 i = first;
7640 first = next[first];
7641 next[i] = UNUSED;
7642 }
7643
7644 count++;
7645
7646 if(count == (cbcount+1)*AVERAGE_COUNT/256)
7647 {
7648 if(cbcount < 256)
7649 {
7650 if(callback)
7651 callback(cbcount);
7652
7653 cbcount++;
7654 }
7655 }
7656 }
7657
7658 if(callback)
7659 while(cbcount < 256)
7660 callback(cbcount++);
7661 }
7662
7663 int32_t short_bmp_avg(BITMAP *bmp, int32_t i)
7664 {
7665 int32_t j=((int16_t *)bmp->line[0])[i];
7666 int32_t r=getr15(j);
7667 int32_t g=getg15(j);
7668 int32_t b=getb15(j);
7669 int32_t k=1;
7670
7671 if(i>0)
7672 {
7673 j=((int16_t *)bmp->line[0])[i-1];
7674 r+=getr15(j);
7675 g+=getg15(j);
7676 b+=getb15(j);
7677 ++k;
7678 }
7679
7680 if(i<(bmp->w-2))
7681 {
7682 j=((int16_t *)bmp->line[0])[i+1];
7683 r+=getr15(j);
7684 g+=getg15(j);
7685 b+=getb15(j);
7686 ++k;
7687 }
7688
7689 r/=k;
7690 g/=k;
7691 b/=k;
7692 return makecol15(r, g, b);
7693 }
7694
7695 // A consistent RENG (random enough number generator) for dither_rect()
7696 static uint16_t lfsr;
7697
7698 void lfsrInit()
7699 {
7700 lfsr=1;
7701 }
7702
7703 uint16_t lfsrNext()
7704 {
7705 auto bits=(lfsr^(lfsr>>2)^(lfsr>>3)^(lfsr>>5))&1;
7706 lfsr=(lfsr>>1)|(bits<<15);
7707 return lfsr;
7708 }
7709
7710 void dither_rect(BITMAP *bmp, PALETTE *pal, int32_t x1, int32_t y1, int32_t x2, int32_t y2,
7711 int32_t src_color1, int32_t src_color2, uint8_t dest_color1,
7712 uint8_t dest_color2)
7713 {
7714 BITMAP *src_bmp=create_bitmap_ex(15, abs(x2-x1)+1, 1);
7715 BITMAP *dest_bmp=create_bitmap_ex(8, abs(x2-x1)+1, abs(y2-y1)+1);
7716 int32_t r, g, b, direction=1;
7717 int32_t c;
7718 int32_t r1, r2, g1, g2, b1, b2;
7719 int32_t (*diff[2])[3];
7720 diff[0] = new int32_t[x2-x1+3][3];
7721 diff[1] = new int32_t[x2-x1+3][3];
7722 int32_t cdiff[3];
7723 RGB_MAP table;
7724 int32_t temp;
7725 int32_t red_rand_strength=0, green_rand_strength=0, blue_rand_strength=0;
7726
7727 lfsrInit();
7728 clear_bitmap(dest_bmp);
7729
7730 if(x1>x2)
7731 {
7732 temp=x1;
7733 x1=x2;
7734 x2=temp;
7735 }
7736
7737 if(y1>y2)
7738 {
7739 temp=y1;
7740 y1=y2;
7741 y2=temp;
7742 }
7743
7744 if(src_color1>src_color2)
7745 {
7746 temp=src_color1;
7747 src_color1=src_color2;
7748 src_color2=temp;
7749 }
7750
7751 if(dest_color1>dest_color2)
7752 {
7753 temp=dest_color1;
7754 dest_color1=dest_color2;
7755 dest_color2=temp;
7756 }
7757
7758 create_rgb_table_range(&table, *pal, dest_color1, dest_color2, NULL);
7759 r1=getr15(src_color1);
7760 r2=getr15(src_color2);
7761 g1=getg15(src_color1);
7762 g2=getg15(src_color2);
7763 b1=getb15(src_color1);
7764 b2=getb15(src_color2);
7765 red_rand_strength=getr8(dest_color1+1)-getr8(dest_color1);
7766 green_rand_strength=getg8(dest_color1+1)-getg8(dest_color1);
7767 blue_rand_strength=getb8(dest_color1+1)-getb8(dest_color1);
7768 memset(cdiff,0,3*sizeof(float));
7769 memset(diff[0],0,(x2-x1+3)*3*sizeof(int32_t));
7770 memset(diff[1],0,(x2-x1+3)*3*sizeof(int32_t));
7771 int32_t mc, mr, mg, mb;
7772
7773 for(int32_t i=0; i<src_bmp->w; i++)
7774 {
7775 r = mix_value(r1, r2, i, src_bmp->w-1);
7776 g = mix_value(g1, g2, i, src_bmp->w-1);
7777 b = mix_value(b1, b2, i, src_bmp->w-1);
7778 c = makecol15(r,g,b);
7779 ((int16_t *)src_bmp->line[0])[i] = c;
7780 }
7781
7782 uint8_t tempcolor, origcolor;
7783
7784 for(int32_t j=0; j<=y2-y1; ++j)
7785 {
7786 if(direction==1)
7787 {
7788 for(int32_t i=0; i<=x2-x1; ++i)
7789 {
7790 mc=((int16_t *)src_bmp->line[0])[i];
7791 mr=bound(getr15(mc)+lfsrNext()%(red_rand_strength*2+1)-(red_rand_strength*1),0,255);
7792 mg=bound(getg15(mc)+lfsrNext()%(green_rand_strength*2+1)-(green_rand_strength*1),0,255);
7793 mb=bound(getb15(mc)+lfsrNext()%(blue_rand_strength*2+1)-(blue_rand_strength*1),0,255);
7794 cdiff[0]=bound(mr+
7795 diff[0][i][0]+
7796 diff[0][i+1][0]+
7797 diff[0][i+2][0]+
7798 cdiff[0],0,255);
7799 cdiff[1]=bound(mg+
7800 diff[0][i][1]+
7801 diff[0][i+1][1]+
7802 diff[0][i+2][1]+
7803 cdiff[1],0,255);
7804 cdiff[2]=bound(mb+
7805 diff[0][i][2]+
7806 diff[0][i+1][2]+
7807 diff[0][i+2][2]+
7808 cdiff[2],0,255);
7809 // bmp->line[j][i+x1]=bound(makecol8_map(int32_t(cdiff[0]),int32_t(cdiff[1]),int32_t(cdiff[2]),&table),dest_color1,dest_color2);
7810 origcolor=makecol8_map(mr,mg,mb,&table);
7811 // tempcolor=bound(makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table),origcolor-1,origcolor+1);
7812 tempcolor=makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table);
7813 dest_bmp->line[j][i]=tempcolor;
7814 r=getr8(tempcolor);
7815 g=getg8(tempcolor);
7816 b=getb8(tempcolor);
7817 diff[1][i][0]=(cdiff[0]-r)*3/16;
7818 diff[1][i][1]=(cdiff[1]-g)*3/16;
7819 diff[1][i][2]=(cdiff[2]-b)*3/16;
7820 diff[1][i+1][0]=(cdiff[0]-r)*5/16;
7821 diff[1][i+1][1]=(cdiff[1]-g)*5/16;
7822 diff[1][i+1][2]=(cdiff[2]-b)*5/16;
7823 diff[1][i+2][0]=(cdiff[0]-r)*1/16;
7824 diff[1][i+2][1]=(cdiff[1]-g)*1/16;
7825 diff[1][i+2][2]=(cdiff[2]-b)*1/16;
7826 cdiff[0]=(cdiff[0]-r)*7/16;
7827 cdiff[1]=(cdiff[1]-g)*7/16;
7828 cdiff[2]=(cdiff[2]-b)*7/16;
7829 }
7830
7831 memcpy(diff[0],diff[1],(x2-x1+3)*3*sizeof(int32_t));
7832 memset(diff[1],0,(x2-x1+3)*3*sizeof(int32_t));
7833 direction=-1;
7834 }
7835 else
7836 {
7837 for(int32_t i=x2-x1; i>=0; --i)
7838 {
7839 mc=((int16_t *)src_bmp->line[0])[i];
7840 mr=getr15(mc);
7841 mg=getg15(mc);
7842 mb=getb15(mc);
7843 cdiff[0]=bound(mr+
7844 diff[0][i][0]+
7845 diff[0][i+1][0]+
7846 diff[0][i+2][0]+
7847 cdiff[0],0,255);
7848 cdiff[1]=bound(mg+
7849 diff[0][i][1]+
7850 diff[0][i+1][1]+
7851 diff[0][i+2][1]+
7852 cdiff[1],0,255);
7853 cdiff[2]=bound(mb+
7854 diff[0][i][2]+
7855 diff[0][i+1][2]+
7856 diff[0][i+2][2]+
7857 cdiff[2],0,255);
7858 // bmp->line[j][i+x1]=bound(makecol8_map(int32_t(cdiff[0]),int32_t(cdiff[1]),int32_t(cdiff[2]),&table),dest_color1,dest_color2);
7859 origcolor=makecol8_map(mr,mg,mb,&table);
7860 // tempcolor=bound(makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table),origcolor-1,origcolor+1);
7861 tempcolor=makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table);
7862 dest_bmp->line[j][i]=tempcolor;
7863 r=getr8(tempcolor);
7864 g=getg8(tempcolor);
7865 b=getb8(tempcolor);
7866 diff[1][i][0]=(cdiff[0]-r)*3/16;
7867 diff[1][i][1]=(cdiff[1]-g)*3/16;
7868 diff[1][i][2]=(cdiff[2]-b)*3/16;
7869 diff[1][i+1][0]=(cdiff[0]-r)*5/16;
7870 diff[1][i+1][1]=(cdiff[1]-g)*5/16;
7871 diff[1][i+1][2]=(cdiff[2]-b)*5/16;
7872 diff[1][i+2][0]=(cdiff[0]-r)*1/16;
7873 diff[1][i+2][1]=(cdiff[1]-g)*1/16;
7874 diff[1][i+2][2]=(cdiff[2]-b)*1/16;
7875 cdiff[0]=(cdiff[0]-r)*7/16;
7876 cdiff[1]=(cdiff[1]-g)*7/16;
7877 cdiff[2]=(cdiff[2]-b)*7/16;
7878 }
7879
7880 memcpy(diff[0],diff[1],(x2-x1+3)*3*sizeof(float));
7881 memset(diff[1],0,(x2-x1+3)*3*sizeof(float));
7882 direction=1;
7883 }
7884 }
7885
7886 blit(dest_bmp, bmp, 0, 0, x1, y1, x2-x1+1, y2-y1+1);
7887 delete[] diff[1];
7888 delete[] diff[0];
7889 destroy_bitmap(src_bmp);
7890 destroy_bitmap(dest_bmp);
7891 return;
7892 }
7893
7894 bool do_text_button(int32_t x,int32_t y,int32_t w,int32_t h,const char *text)
7895 {
7896 bool over=false;
7897
7898 while(gui_mouse_b())
7899 {
7900 if(mouse_in_rect(x,y,w,h))
7901 {
7902 if(!over)
7903 {
7904 vsync();
7905 jwin_draw_text_button(screen, x, y, w, h, text, D_SELECTED, true);
7906 over=true;
7907 update_hw_screen();
7908 }
7909 }
7910 else
7911 {
7912 if(over)
7913 {
7914 vsync();
7915 jwin_draw_text_button(screen, x, y, w, h, text, 0, true);
7916 over=false;
7917 update_hw_screen();
7918 }
7919 }
7920 rest(1);
7921 }
7922
7923 return over;
7924 }
7925
7926 bool do_text_button_reset(int32_t x,int32_t y,int32_t w,int32_t h,const char *text)
7927 {
7928 bool over=false;
7929
7930 while(gui_mouse_b())
7931 {
7932 //vsync();
7933 if(mouse_in_rect(x,y,w,h))
7934 {
7935 if(!over)
7936 {
7937 vsync();
7938 jwin_draw_text_button(screen, x, y, w, h, text, D_SELECTED, true);
7939 over=true;
7940
7941 update_hw_screen();
7942 }
7943 }
7944 else
7945 {
7946 if(over)
7947 {
7948 vsync();
7949 jwin_draw_text_button(screen, x, y, w, h, text, 0, true);
7950 over=false;
7951
7952 update_hw_screen();
7953 }
7954 }
7955 rest(1);
7956 }
7957
7958 if(over)
7959 {
7960 vsync();
7961 jwin_draw_text_button(screen, x, y, w, h, text, 0, true);
7962
7963 update_hw_screen();
7964 }
7965
7966 return over;
7967 }
7968 bool do_icon_button_reset(int32_t x,int32_t y,int32_t w,int32_t h,int icon)
7969 {
7970 bool over=false;
7971
7972 while(gui_mouse_b())
7973 {
7974 //vsync();
7975 if(mouse_in_rect(x,y,w,h))
7976 {
7977 if(!over)
7978 {
7979 vsync();
7980 jwin_draw_icon_button(screen, x, y, w, h, icon, D_SELECTED, true);
7981 over=true;
7982
7983 update_hw_screen();
7984 }
7985 }
7986 else
7987 {
7988 if(over)
7989 {
7990 vsync();
7991 jwin_draw_icon_button(screen, x, y, w, h, icon, 0, true);
7992 over=false;
7993
7994 update_hw_screen();
7995 }
7996 }
7997 rest(1);
7998 }
7999
8000 if(over)
8001 {
8002 vsync();
8003 jwin_draw_icon_button(screen, x, y, w, h, icon, 0, true);
8004
8005 update_hw_screen();
8006 }
8007
8008 return over;
8009 }
8010
8011 int32_t jwin_tab_proc(int32_t msg, DIALOG *d, int32_t c)
8012 {
8013 int32_t i;
8014 int32_t tx;
8015 int32_t sd=2; //selected delta
8016 TABPANEL *panel=(TABPANEL *)d->dp;
8017 DIALOG *panel_dialog=NULL, *current_object=NULL;
8018 int32_t selected=0;
8019 int32_t counter=0;
8020 ASSERT(d);
8021 int32_t temp_d, temp_d2;
8022
8023 if(d->dp==NULL) return D_O_K;
8024
8025 panel_dialog=(DIALOG *)d->dp3;
8026
8027 if (msg != MSG_START && msg != MSG_END)
8028 {
8029 bool redraw = false;
8030 for (i = 0; panel[i].text; ++i)
8031 {
8032 if ((panel[i].flags & D_SELECTED) && !(d->flags & D_HIDDEN))
8033 {
8034 for (counter = 0; counter < panel[i].objects; counter++)
8035 {
8036 current_object = panel_dialog + (panel[i].dialog[counter]);
8037 current_object->flags &= ~D_HIDDEN;
8038 if (object_message(current_object, MSG_IDLE, 0) & D_REDRAW)
8039 redraw = true;
8040 }
8041 }
8042 else
8043 {
8044 for (counter = 0; counter < panel[i].objects; counter++)
8045 {
8046 current_object = panel_dialog + (panel[i].dialog[counter]);
8047 current_object->flags |= D_HIDDEN;
8048 if (object_message(current_object, MSG_IDLE, 0) & D_REDRAW)
8049 redraw = true;
8050 }
8051 }
8052
8053 /*if (d->flags & D_HIDDEN)
8054 {
8055 for(counter=0; counter<panel[i].objects; counter++)
8056 {
8057 current_object=panel_dialog+(panel[i].dialog[counter]);
8058 current_object->x=zq_screen_w*3;
8059 current_object->y=zq_screen_h*3;
8060 }
8061 }*/
8062 }
8063 if (redraw)
8064 broadcast_dialog_message(MSG_DRAW, 0);
8065 }
8066 FONT *oldfont = font;
8067 switch(msg)
8068 {
8069 case MSG_DRAW:
8070 {
8071 if(d->x<zq_screen_w&&d->y<zq_screen_h)
8072 {
8073 if(d->dp2)
8074 {
8075 font = (FONT *)d->dp2;
8076 }
8077
8078 panel_dialog=(DIALOG *)d->dp3;
8079 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+8+text_height(font), scheme[jcBOX]); //tab area
8080 rectfill(screen, d->x+1, d->y+sd+text_height(font)+7, d->x+d->w-2, d->y+sd+d->h-2, scheme[jcBOX]); //panel
8081 vline(screen, d->x, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcLIGHT]);
8082 vline(screen, d->x+1, d->y+sd+7+text_height(font), d->y+sd+d->h-3, scheme[jcMEDLT]);
8083 vline(screen, d->x+d->w-2, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcMEDDARK]);
8084 vline(screen, d->x+d->w-1, d->y+sd+7+text_height(font)-1, d->y+sd+d->h-1, scheme[jcDARK]);
8085 hline(screen, d->x+1, d->y+sd+d->h-2, d->x+d->w-3, scheme[jcMEDDARK]);
8086 hline(screen, d->x, d->y+sd+d->h-1, d->x+d->w-2, scheme[jcDARK]);
8087 tx=d->x;
8088
8089 if(d->dp)
8090 {
8091 if(!(panel[((d->d1&0xFF00)>>8)].flags&D_SELECTED))
8092 {
8093 hline(screen, tx+1, d->y+sd+6+text_height(font)+1, tx+2, scheme[jcMEDLT]); //initial bottom
8094 hline(screen, tx, d->y+sd+6+text_height(font), tx+1, scheme[jcLIGHT]); //initial bottom
8095 }
8096
8097 tx+=2;
8098
8099 for(i=0; panel[i].text; ++i)
8100 {
8101 if(panel[i].flags&D_SELECTED)
8102 {
8103 selected=i;
8104 }
8105 }
8106
8107 for(i=((d->d1&0xFF00)>>8); panel[i].text&&i<=last_visible_tab(panel,((d->d1&0xFF00)>>8),d->w); ++i)
8108 {
8109 sd=(panel[i].flags&D_SELECTED)?0:2;
8110
8111 if((i==((d->d1&0xFF00)>>8)) || (!(panel[i-1].flags&D_SELECTED)))
8112 {
8113 vline(screen, tx-(2-sd), d->y+sd+2, d->y+8+text_height(font), scheme[jcLIGHT]); //left side
8114 vline(screen, tx-(2-sd)+1, d->y+sd+2, d->y+8+text_height(font), scheme[jcMEDLT]); //left side
8115 putpixel(screen, tx+1-(2-sd), d->y+sd+1, scheme[jcLIGHT]); //left angle
8116 }
8117
8118 hline(screen, tx+2-(2-sd), d->y+sd, tx+12+(2-sd)+text_length(font, (char *)panel[i].text), scheme[jcLIGHT]); //top
8119 hline(screen, tx+2-(2-sd), d->y+sd+1, tx+12+(2-sd)+text_length(font, (char *)panel[i].text), scheme[jcMEDLT]); //top
8120
8121 if(!(panel[i].flags&D_SELECTED))
8122 {
8123 hline(screen, tx+1, d->y+sd+6+text_height(font), tx+13+text_length(font, (char *)panel[i].text)+1, scheme[jcLIGHT]); //bottom
8124 hline(screen, tx, d->y+sd+6+text_height(font)+1, tx+13+text_length(font, (char *)panel[i].text)+1, scheme[jcMEDLT]); //bottom
8125 }
8126
8127 tx+=4;
8128 gui_textout_ln(screen, (uint8_t*)panel[i].text, tx+4, d->y+sd+4, scheme[jcBOXFG], scheme[jcBOX], 0);
8129 tx+=text_length(font, (char *)panel[i].text)+10;
8130
8131 if(!(panel[i+1].text) || (!(panel[i+1].flags&D_SELECTED)))
8132 {
8133 putpixel(screen, tx-1+(2-sd), d->y+sd+1, scheme[jcDARK]); //right angle
8134 vline(screen, tx+(2-sd), d->y+sd+2, d->y+8+text_height(font)-1, scheme[jcDARK]); //right side
8135 vline(screen, tx+(2-sd)-1, d->y+sd+2, d->y+8+text_height(font)-(sd?1:0), scheme[jcMEDDARK]); //right side
8136 }
8137
8138 tx++;
8139 }
8140
8141 if(((d->d1&0xFF00)>>8)!=0||last_visible_tab(panel,((d->d1&0xFF00)>>8),d->w)+1<tab_count(panel))
8142 {
8143 jwin_draw_icon_button(screen,d->x+d->w-14,d->y+2, 14, 14, BTNICON_ARROW_RIGHT, 0, true);
8144 jwin_draw_icon_button(screen,d->x+d->w-28,d->y+2, 14, 14, BTNICON_ARROW_LEFT, 0, true);
8145 }
8146 }
8147
8148 if((tx+(2-sd))<(d->x+d->w))
8149 {
8150 hline(screen, tx+(2-sd)-1, d->y+8+text_height(font), d->x+d->w-1, scheme[jcLIGHT]); //ending bottom
8151 hline(screen, tx+(2-sd)-2, d->y+8+text_height(font)+1, d->x+d->w-2, scheme[jcMEDLT]); //ending bottom
8152 }
8153
8154 font = oldfont;
8155
8156 //what dialog is this tab control in (programmer must set manually)
8157 panel_dialog=(DIALOG *)d->dp3;
8158
8159 //for each object handled by the currently selected tab...
8160 for(counter=0; counter<panel[selected].objects; counter++)
8161 {
8162 //assign current_object to one of the controls handled by the tab
8163 current_object=panel_dialog+(panel[selected].dialog[counter]);
8164 //remember the x and y positions of the control
8165 current_object->x=panel[selected].xy[counter*2];
8166 current_object->y=panel[selected].xy[counter*2+1];
8167 object_message(current_object, MSG_DRAW, 0);
8168 }
8169
8170 //if there was a previously selected tab...
8171 if((d->d1&0x00FF)!=0x00FF)
8172 {
8173 //for each object handled by the tab
8174 for(counter=0; counter<panel[d->d1&0xFF].objects; counter++)
8175 {
8176 //assign current_object to one of the controls handled by the tab
8177 current_object=panel_dialog+(panel[d->d1&0xFF].dialog[counter]);
8178 // //remember the x and y positions of the control
8179 // panel[d->d1].xy[counter*2]=current_object->x;
8180 // panel[d->d1].xy[counter*2+1]=current_object->y;
8181 current_object->x=zq_screen_w*3;
8182 current_object->y=zq_screen_h*3;
8183 }
8184 }
8185 }
8186 }
8187 break;
8188
8189 case MSG_CLICK:
8190 {
8191 d->d1&=0xFF00;
8192 d->d1|=0x00FF;
8193 if(d->dp2)
8194 {
8195 font = (FONT *)d->dp2;
8196 }
8197
8198 // is the mouse on one of the tab arrows (if visible) or in the tab area?
8199 if(uses_tab_arrows(panel, d->w)&&(mouse_in_rect(d->x+d->w-28, d->y+2, 28, 14)))
8200 {
8201 if(mouse_in_rect(d->x+d->w-28, d->y+2, 14, 14))
8202 {
8203 if(do_icon_button_reset(d->x+d->w-28, d->y+2, 14, 14, BTNICON_ARROW_LEFT))
8204 {
8205 temp_d=((d->d1&0xFF00)>>8);
8206 temp_d2=(d->d1&0x00FF);
8207
8208 if(temp_d>0)
8209 {
8210 --temp_d;
8211 }
8212
8213 d->d1=(temp_d<<8)|temp_d2;
8214 d->flags|=D_DIRTY;
8215 }
8216 }
8217 else if(mouse_in_rect(d->x+d->w-14, d->y+2, 14, 14))
8218 {
8219 if(do_icon_button_reset(d->x+d->w-14, d->y+2, 14, 14, BTNICON_ARROW_RIGHT))
8220 {
8221 temp_d=((d->d1&0xFF00)>>8);
8222 temp_d2=(d->d1&0x00FF);
8223
8224 if(last_visible_tab(panel, temp_d, d->w)<(tab_count(panel)-1))
8225 {
8226 ++temp_d;
8227 }
8228
8229 d->d1=(temp_d<<8)|temp_d2;
8230 d->flags|=D_DIRTY;
8231 }
8232 }
8233 }
8234 else
8235 {
8236 d_tab_proc(msg, d, c);
8237 }
8238 font = oldfont;
8239 jwin_tab_proc(MSG_IDLE,d,0);
8240 }
8241 break;
8242
8243 default:
8244 return d_tab_proc(msg, d, c);
8245 break;
8246 }
8247
8248 panel_dialog=(DIALOG *)d->dp3;
8249
8250 if(d->flags & D_HIDDEN)
8251 {
8252 for(i=0; panel[i].text; ++i)
8253 {
8254 for(counter=0; counter<panel[i].objects; counter++)
8255 {
8256 current_object=panel_dialog+(panel[i].dialog[counter]);
8257 current_object->x=zq_screen_w*3;
8258 current_object->y=zq_screen_h*3;
8259 }
8260 }
8261
8262 //d->x=zq_screen_w*3;
8263 //d->y=zq_screen_h*3;
8264 }
8265 else
8266 {
8267 for(i=0; panel[i].text; ++i)
8268 {
8269 for(counter=0; counter<panel[i].objects; counter++)
8270 {
8271 current_object=panel_dialog+(panel[i].dialog[counter]);
8272 current_object->x=panel[i].xy[counter*2];
8273 current_object->y=panel[i].xy[counter*2+1];
8274 }
8275 }
8276
8277 // d->x=zq_screen_w*3;
8278 //d->y=zq_screen_h*3;
8279 }
8280
8281 return broadcast_dialog_message(MSG_IDLE, 0);
8282
8283 // return D_O_K;
8284 }
8285
8286 int32_t discern_tab(GUI::TabPanel *panel, int32_t first_tab, int32_t x)
8287 {
8288 int32_t w=0;
8289
8290 for(size_t i=first_tab; i < panel->getSize(); i++)
8291 {
8292 w+=text_length(font, panel->getName(i))+15;
8293
8294 if(w>x)
8295 {
8296 return i;
8297 }
8298 }
8299
8300 return -1;
8301 }
8302 int32_t tabs_width(GUI::TabPanel *panel)
8303 {
8304 int32_t w=0;
8305
8306 for(size_t i=0; i < panel->getSize(); ++i)
8307 {
8308 w+=text_length(font, panel->getName(i))+15;
8309 }
8310
8311 return w+1;
8312 }
8313 bool uses_tab_arrows(GUI::TabPanel *panel, int32_t maxwidth)
8314 {
8315 return (tabs_width(panel)>maxwidth);
8316 }
8317 size_t last_visible_tab(GUI::TabPanel *panel, int32_t first_tab, int32_t maxwidth)
8318 {
8319 size_t i;
8320 int32_t w=0;
8321
8322 if(uses_tab_arrows(panel, maxwidth))
8323 {
8324 maxwidth-=28;
8325 }
8326
8327 for(i=first_tab; i < panel->getSize(); ++i)
8328 {
8329 w+=text_length(font, panel->getName(i))+15;
8330
8331 if(w>maxwidth)
8332 {
8333 return i-1;
8334 }
8335 }
8336
8337 return i-1;
8338 }
8339 int32_t displayed_tabs_width(GUI::TabPanel *panel, int32_t first_tab, int32_t maxwidth)
8340 {
8341 size_t i=0;
8342 int32_t w=0;
8343
8344 for(i=first_tab; i<=last_visible_tab(panel, first_tab, maxwidth); ++i)
8345 {
8346 w+=text_length(font, panel->getName(i))+15;
8347 }
8348
8349 return w+1;
8350 }
8351
8352 INLINE int32_t is_in_rect(int32_t x,int32_t y,int32_t rx1,int32_t ry1,int32_t rx2,int32_t ry2)
8353 {
8354 return x>=rx1 && x<=rx2 && y>=ry1 && y<=ry2;
8355 }
8356
8357 int32_t new_tab_proc(int32_t msg, DIALOG *d, int32_t c)
8358 {
8359 assert(d->flags&D_NEW_GUI);
8360
8361 int32_t tx;
8362 int32_t ret = D_O_K;
8363 int32_t sd=2; //selected delta
8364 static bool skipredraw = false;
8365 GUI::TabPanel *panel=(GUI::TabPanel*)d->dp;
8366 ASSERT(d);
8367
8368 if(d->dp==NULL) return D_O_K;
8369
8370 FONT *oldfont = font;
8371 if(d->dp2)
8372 {
8373 font = (FONT *)d->dp2;
8374 }
8375
8376 switch(msg)
8377 {
8378 case MSG_DRAW:
8379 {
8380 if(skipredraw)
8381 {
8382 skipredraw = false;
8383 ret = D_REDRAW;
8384 break;
8385 }
8386 if(d->x<zq_screen_w&&d->y<zq_screen_h)
8387 {
8388 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+8+text_height(font), scheme[jcBOX]); //tab area
8389 rectfill(screen, d->x+1, d->y+sd+text_height(font)+7, d->x+d->w-2, d->y+sd+d->h-2, scheme[jcBOX]); //panel
8390 vline(screen, d->x, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcLIGHT]);
8391 vline(screen, d->x+1, d->y+sd+7+text_height(font), d->y+sd+d->h-3, scheme[jcMEDLT]);
8392 vline(screen, d->x+d->w-2, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcMEDDARK]);
8393 vline(screen, d->x+d->w-1, d->y+sd+7+text_height(font)-1, d->y+sd+d->h-1, scheme[jcDARK]);
8394 hline(screen, d->x+1, d->y+sd+d->h-2, d->x+d->w-3, scheme[jcMEDDARK]);
8395 hline(screen, d->x, d->y+sd+d->h-1, d->x+d->w-2, scheme[jcDARK]);
8396 tx=d->x;
8397
8398 if(d->dp)
8399 {
8400 if(panel->getCurrentIndex() != d->d1)
8401 {
8402 hline(screen, tx+1, d->y+sd+6+text_height(font)+1, tx+2, scheme[jcMEDLT]); //initial bottom
8403 hline(screen, tx, d->y+sd+6+text_height(font), tx+1, scheme[jcLIGHT]); //initial bottom
8404 }
8405
8406 tx+=2;
8407
8408 for(size_t i=d->d1; i < panel->getSize()&&i<=last_visible_tab(panel,d->d1,d->w); ++i)
8409 {
8410 sd=(i==panel->getCurrentIndex())?0:2;
8411
8412 if((i==d->d1) || (i-1 != panel->getCurrentIndex()))
8413 {
8414 vline(screen, tx-(2-sd), d->y+sd+2, d->y+8+text_height(font), scheme[jcLIGHT]); //left side
8415 vline(screen, tx-(2-sd)+1, d->y+sd+2, d->y+8+text_height(font), scheme[jcMEDLT]); //left side
8416 putpixel(screen, tx+1-(2-sd), d->y+sd+1, scheme[jcLIGHT]); //left angle
8417 }
8418
8419 hline(screen, tx+2-(2-sd), d->y+sd, tx+12+(2-sd)+text_length(font, panel->getName(i)), scheme[jcLIGHT]); //top
8420 hline(screen, tx+2-(2-sd), d->y+sd+1, tx+12+(2-sd)+text_length(font, panel->getName(i)), scheme[jcMEDLT]); //top
8421
8422 if(i!=panel->getCurrentIndex())
8423 {
8424 hline(screen, tx+1, d->y+sd+6+text_height(font), tx+13+text_length(font, panel->getName(i))+1, scheme[jcLIGHT]); //bottom
8425 hline(screen, tx, d->y+sd+6+text_height(font)+1, tx+13+text_length(font, panel->getName(i))+1, scheme[jcMEDLT]); //bottom
8426 }
8427 else if(d->flags & D_GOTFOCUS)
8428 {
8429 hline(screen, tx+1, d->y+sd+6+text_height(font), tx+13+text_length(font, panel->getName(i))+1, scheme[jcBOXFG]); //bottom
8430 hline(screen, tx, d->y+sd+6+text_height(font)+1, tx+13+text_length(font, panel->getName(i))+1, scheme[jcBOXFG]); //bottom
8431 }
8432
8433 tx+=4;
8434 uint8_t* pname = (uint8_t*)(panel->getName(i));
8435 bool dis = panel->getDisabled(i);
8436 if(dis)
8437 gui_textout_ln(screen, pname, tx+5, d->y+sd+5, scheme[jcLIGHT], scheme[jcBOX], 0);
8438 gui_textout_ln(screen, pname, tx+4, d->y+sd+4, scheme[dis ? jcDISABLED_FG : jcBOXFG], dis ? -1 : scheme[jcBOX], 0);
8439 tx+=text_length(font, (const char*)pname)+10;
8440
8441 if((i+1>=panel->getSize()) || (i+1!=panel->getCurrentIndex()))
8442 {
8443 putpixel(screen, tx-1+(2-sd), d->y+sd+1, scheme[jcDARK]); //right angle
8444 vline(screen, tx+(2-sd), d->y+sd+2, d->y+8+text_height(font)-1, scheme[jcDARK]); //right side
8445 vline(screen, tx+(2-sd)-1, d->y+sd+2, d->y+8+text_height(font)-(sd?1:0), scheme[jcMEDDARK]); //right side
8446 }
8447
8448 tx++;
8449 }
8450
8451 if(d->d1!=0||last_visible_tab(panel,d->d1,d->w)+1<panel->getSize())
8452 {
8453 jwin_draw_icon_button(screen,d->x+d->w-14,d->y+2, 14, 14, BTNICON_ARROW_RIGHT, 0, true);
8454 jwin_draw_icon_button(screen,d->x+d->w-28,d->y+2, 14, 14, BTNICON_ARROW_LEFT, 0, true);
8455 }
8456 }
8457
8458 if((tx+(2-sd))<(d->x+d->w))
8459 {
8460 hline(screen, tx+(2-sd)-1, d->y+8+text_height(font), d->x+d->w-1, scheme[jcLIGHT]); //ending bottom
8461 hline(screen, tx+(2-sd)-2, d->y+8+text_height(font)+1, d->x+d->w-2, scheme[jcMEDLT]); //ending bottom
8462 }
8463
8464 }
8465 }
8466 break;
8467
8468 case MSG_WANTFOCUS:
8469 // if(gui_mouse_b())
8470 ret = D_WANTFOCUS|D_REDRAW;
8471 break;
8472 case MSG_GOTFOCUS:
8473 case MSG_LOSTFOCUS:
8474 skipredraw = true;
8475 break;
8476 case MSG_CHAR:
8477 {
8478 int32_t ind = panel->getCurrentIndex();
8479 auto oldind = ind;
8480 switch(c>>8)
8481 {
8482 case KEY_LEFT:
8483 do
8484 {
8485 if(ind > 0)
8486 {
8487 --ind;
8488 }
8489 else
8490 {
8491 ind = panel->getSize()-1;
8492 }
8493 }
8494 while(ind != oldind && panel->getDisabled(ind));
8495 break;
8496 case KEY_RIGHT:
8497 do
8498 {
8499 if(ind+1 < signed(panel->getSize()))
8500 {
8501 ++ind;
8502 }
8503 else
8504 {
8505 ind = 0;
8506 }
8507 }
8508 while(ind != oldind && panel->getDisabled(ind));
8509 break;
8510 default: ind = -1;
8511 }
8512 if(ind > -1 && ind != oldind)
8513 {
8514 panel->switchTo(ind);
8515 GUI_EVENT(d, geCHANGE_SELECTION);
8516 ret |= D_USED_CHAR;
8517 }
8518 }
8519 break;
8520
8521 case MSG_CLICK:
8522 {
8523 // is the mouse on one of the tab arrows (if visible) or in the tab area?
8524 if(uses_tab_arrows(panel, d->w)&&(mouse_in_rect(d->x+d->w-28, d->y+2, 28, 14)))
8525 {
8526 if(mouse_in_rect(d->x+d->w-28, d->y+2, 14, 14))
8527 {
8528 if(do_icon_button_reset(d->x+d->w-28, d->y+2, 14, 14, BTNICON_ARROW_LEFT))
8529 {
8530 if(d->d1>0)
8531 {
8532 --d->d1;
8533 }
8534
8535 ret |= D_REDRAW;
8536 }
8537 }
8538 else if(mouse_in_rect(d->x+d->w-14, d->y+2, 14, 14))
8539 {
8540 if(do_icon_button_reset(d->x+d->w-14, d->y+2, 14, 14, BTNICON_ARROW_RIGHT))
8541 {
8542 size_t t = last_visible_tab(panel, d->d1, d->w);
8543 if(t<(panel->getSize()-1))
8544 {
8545 while(t==last_visible_tab(panel, d->d1, d->w))
8546 ++d->d1;
8547 }
8548
8549 ret |= D_REDRAW;
8550 }
8551 }
8552 }
8553 else if(is_in_rect(gui_mouse_x(),gui_mouse_y(), d->x+2, d->y+2, d->x+displayed_tabs_width(panel,((d->d1&0xFF00)>>8),d->w), d->y+text_height(font)+9))
8554 {
8555 // find out what the new tab (tb) will be (where the mouse is)
8556 int32_t newtab = discern_tab(panel, d->d1, gui_mouse_x()-d->x-2);
8557 if(newtab > -1 && newtab != panel->getCurrentIndex() && !panel->getDisabled(newtab))
8558 {
8559 panel->switchTo(newtab);
8560 GUI_EVENT(d, geCHANGE_SELECTION);
8561 }
8562 }
8563 }
8564 break;
8565 }
8566 font = oldfont;
8567 return ret;
8568 }
8569
8570
8571
8572
8573 int32_t jwin_hline_proc(int32_t msg, DIALOG *d, int32_t)
8574 {
8575 ASSERT(d);
8576
8577 if(msg==MSG_DRAW)
8578 {
8579 if(d->w < 1) return D_O_K;
8580 for(int q = 0; q <= d->d1; ++q)
8581 {
8582 if(d->d2&1)
8583 {
8584 hline(screen, d->x, d->y+q, d->x+d->w-1, d->fg);
8585 }
8586 else
8587 {
8588 hline(screen, d->x, d->y-q, d->x+d->w-1, scheme[jcMEDDARK]);
8589 hline(screen, d->x, d->y+1+q, d->x+d->w-1, scheme[jcLIGHT]);
8590 }
8591 }
8592 }
8593
8594 return D_O_K;
8595 }
8596
8597 int32_t jwin_vline_proc(int32_t msg, DIALOG *d, int32_t)
8598 {
8599 ASSERT(d);
8600
8601 if(msg==MSG_DRAW)
8602 {
8603 if(d->h < 1) return D_O_K;
8604 for(int q = 0; q <= d->d1; ++q)
8605 {
8606 if(d->d2&1)
8607 {
8608 vline(screen, d->x+q, d->y, d->y+d->h-1, d->fg);
8609 }
8610 else
8611 {
8612 vline(screen, d->x+q, d->y, d->y+d->h-1, scheme[jcMEDDARK]);
8613 vline(screen, d->x+1-q, d->y, d->y+d->h-1, scheme[jcLIGHT]);
8614 }
8615 }
8616 }
8617
8618 return D_O_K;
8619 }
8620
8621 int32_t jwin_editbox_proc(int32_t msg, DIALOG *d, int32_t c)
8622 {
8623 return d_editbox_proc(msg, d, c);
8624 }
8625
8626 //centers dialog based on first object, which should be the containing window
8627 4288 void jwin_center_dialog(DIALOG *dialog)
8628 {
8629 int32_t xc, yc;
8630 int32_t c;
8631 ASSERT(dialog);
8632
8633 /* how much to move by? */
8634 4288 xc = (zq_screen_w - dialog[0].w) / 2 - dialog[0].x;
8635 4288 yc = (zq_screen_h - dialog[0].h) / 2 - dialog[0].y;
8636
8637 /* move it */
8638
2/2
✓ Branch 0 taken 91953 times.
✓ Branch 1 taken 4288 times.
96241 for(c=0; dialog[c].proc; c++)
8639 {
8640 91953 dialog[c].x += xc;
8641 91953 dialog[c].y += yc;
8642 91953 }
8643 4288 }
8644 //up-left aligns dialog based on first object, which should be the containing window
8645 void jwin_ulalign_dialog(DIALOG *dialog)
8646 {
8647 int32_t xc, yc;
8648 int32_t c;
8649 ASSERT(dialog);
8650
8651 /* how much to move by? */
8652 xc = dialog[0].x;
8653 yc = dialog[0].y;
8654
8655 /* move it */
8656 for(c=0; dialog[c].proc; c++)
8657 {
8658 dialog[c].x -= xc;
8659 dialog[c].y -= yc;
8660 }
8661 }
8662
8663 //Custom slider proc
8664 int32_t d_jslider_proc(int32_t msg, DIALOG *d, int32_t c)
8665 {
8666 BITMAP *gui_bmp = screen;
8667 BITMAP *slhan = NULL;
8668 int32_t oldpos, newpos;
8669 int32_t sfg; /* slider foreground color */
8670 int32_t vert = TRUE; /* flag: is slider vertical? */
8671 int32_t hh = 7; /* handle height (width for horizontal sliders) */
8672 int32_t hmar; /* handle margin */
8673 int32_t slp; /* slider position */
8674 int32_t mp; /* mouse position */
8675 int32_t irange;
8676 int32_t slx, sly, slh, slw;
8677 int32_t msx, msy;
8678 int32_t retval = D_O_K;
8679 int32_t upkey, downkey;
8680 int32_t pgupkey, pgdnkey;
8681 int32_t homekey, endkey;
8682 int32_t delta;
8683 fixed slratio, slmax, slpos;
8684 typedef int32_t (*SLIDER_TYPE)(void*, int32_t);
8685 SLIDER_TYPE proc = NULL;
8686 //int32_t (*proc)(void *cbpointer, int32_t d2value);
8687 int32_t oldval;
8688 ASSERT(d);
8689
8690 /* check for slider direction */
8691 if(d->h < d->w)
8692 vert = FALSE;
8693
8694 /* set up the metrics for the control */
8695 if(d->dp != NULL)
8696 {
8697 slhan = (BITMAP *)d->dp;
8698
8699 if(vert)
8700 hh = slhan->h;
8701 else
8702 hh = slhan->w;
8703 }
8704
8705 hmar = hh/2;
8706 irange = (vert) ? d->h : d->w;
8707 slmax = itofix(irange-hh);
8708 slratio = slmax / (d->d1);
8709 slpos = slratio * d->d2;
8710 slp = fixtoi(slpos);
8711
8712 switch(msg)
8713 {
8714
8715 case MSG_DRAW:
8716 sfg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
8717
8718 if(vert)
8719 {
8720 rectfill(gui_bmp, d->x, d->y, d->x+d->w/2-2, d->y+d->h-1, d->bg);
8721 rectfill(gui_bmp, d->x+d->w/2-1, d->y, d->x+d->w/2+1, d->y+d->h-1, sfg);
8722 rectfill(gui_bmp, d->x+d->w/2+2, d->y, d->x+d->w-1, d->y+d->h-1, d->bg);
8723 }
8724 else
8725 {
8726 rectfill(gui_bmp, d->x, d->y, d->x+d->w-1, d->y+d->h/2-2, d->bg);
8727 rectfill(gui_bmp, d->x, d->y+d->h/2-1, d->x+d->w-1, d->y+d->h/2+1, sfg);
8728 rectfill(gui_bmp, d->x, d->y+d->h/2+2, d->x+d->w-1, d->y+d->h-1, d->bg);
8729 }
8730
8731 /* okay, background and slot are drawn, now draw the handle */
8732 if(slhan)
8733 {
8734 if(vert)
8735 {
8736 slx = d->x+(d->w/2)-(slhan->w/2);
8737 sly = d->y+(d->h-1)-(hh+slp);
8738 }
8739 else
8740 {
8741 slx = d->x+slp;
8742 sly = d->y+(d->h/2)-(slhan->h/2);
8743 }
8744
8745 draw_sprite(gui_bmp, slhan, slx, sly);
8746 }
8747 else
8748 {
8749 /* draw default handle */
8750 if(vert)
8751 {
8752 slx = d->x;
8753 sly = d->y+(d->h)-(hh+slp);
8754 slw = d->w-1;
8755 slh = hh-1;
8756 }
8757 else
8758 {
8759 slx = d->x+slp;
8760 sly = d->y;
8761 slw = hh-1;
8762 slh = d->h-1;
8763 }
8764
8765 /* draw body */
8766 rectfill(gui_bmp, slx+2, sly, slx+(slw-2), sly+slh, sfg);
8767 vline(gui_bmp, slx+1, sly+1, sly+slh-1, sfg);
8768 vline(gui_bmp, slx+slw-1, sly+1, sly+slh-1, sfg);
8769 vline(gui_bmp, slx, sly+2, sly+slh-2, sfg);
8770 vline(gui_bmp, slx+slw, sly+2, sly+slh-2, sfg);
8771 vline(gui_bmp, slx+1, sly+2, sly+slh-2, d->bg);
8772 hline(gui_bmp, slx+2, sly+1, slx+slw-2, d->bg);
8773 putpixel(gui_bmp, slx+2, sly+2, d->bg);
8774 }
8775
8776 if(d->flags & D_GOTFOCUS)
8777 dotted_rect(gui_bmp, d->x, d->y, d->x+d->w-1, d->y+d->h-1, sfg, d->bg);
8778
8779 break;
8780
8781 case MSG_WANTFOCUS:
8782 case MSG_LOSTFOCUS:
8783 return D_WANTFOCUS;
8784
8785 case MSG_KEY:
8786 if(!(d->flags & D_GOTFOCUS))
8787 return D_WANTFOCUS;
8788 else
8789 return D_O_K;
8790
8791 case MSG_CHAR:
8792 /* handle movement keys to move slider */
8793 c >>= 8;
8794
8795 if(vert)
8796 {
8797 upkey = KEY_UP;
8798 downkey = KEY_DOWN;
8799 pgupkey = KEY_PGUP;
8800 pgdnkey = KEY_PGDN;
8801 homekey = KEY_END;
8802 endkey = KEY_HOME;
8803 }
8804 else
8805 {
8806 upkey = KEY_RIGHT;
8807 downkey = KEY_LEFT;
8808 pgupkey = KEY_PGDN;
8809 pgdnkey = KEY_PGUP;
8810 homekey = KEY_HOME;
8811 endkey = KEY_END;
8812 }
8813
8814 if(c == upkey)
8815 delta = 1;
8816 else if(c == downkey)
8817 delta = -1;
8818 else if(c == pgdnkey)
8819 delta = -d->d1 / 16;
8820 else if(c == pgupkey)
8821 delta = d->d1 / 16;
8822 else if(c == homekey)
8823 delta = -d->d2;
8824 else if(c == endkey)
8825 delta = d->d1 - d->d2;
8826 else
8827 delta = 0;
8828
8829 if(delta)
8830 {
8831 oldpos = slp;
8832 oldval = d->d2;
8833
8834 //while (true) {
8835 for(; ;) //thank you, MSVC ~pkmnfrk
8836 {
8837 d->d2 = d->d2+delta;
8838 slpos = slratio*d->d2;
8839 slp = fixtoi(slpos);
8840
8841 if((slp != oldpos) || (d->d2 <= 0) || (d->d2 >= d->d1))
8842 break;
8843 }
8844
8845 if(d->d2 < 0)
8846 d->d2 = 0;
8847
8848 if(d->d2 > d->d1)
8849 d->d2 = d->d1;
8850
8851 retval = D_USED_CHAR;
8852
8853 if(d->d2 != oldval)
8854 {
8855 /* call callback function here */
8856 if(d->dp2)
8857 {
8858 proc = (SLIDER_TYPE)(d->dp2);
8859 retval |= (*proc)(d->dp3, d->d2);
8860 }
8861
8862 GUI_EVENT(d, geCHANGE_VALUE);
8863
8864 object_message(d, MSG_DRAW, 0);
8865 }
8866 }
8867
8868 break;
8869
8870 case MSG_WANTWHEEL:
8871 return 1;
8872
8873 case MSG_WHEEL:
8874 oldval = d->d2;
8875 d->d2 = MID(0, d->d2+c, d->d1);
8876
8877 if(d->d2 != oldval)
8878 {
8879 /* call callback function here */
8880 if(d->dp2)
8881 {
8882 proc = (SLIDER_TYPE)(d->dp2);
8883 retval |= (*proc)(d->dp3, d->d2);
8884 }
8885
8886 GUI_EVENT(d, geCHANGE_VALUE);
8887 object_message(d, MSG_DRAW, 0);
8888 retval |= D_REDRAWME;
8889 }
8890
8891 break;
8892
8893 case MSG_CLICK:
8894 /* track the mouse until it is released */
8895 mp = slp;
8896
8897 while(gui_mouse_b())
8898 {
8899 msx = gui_mouse_x();
8900 msy = gui_mouse_y();
8901 oldval = d->d2;
8902
8903 if(vert)
8904 mp = (d->y+d->h-hmar)-msy;
8905 else
8906 mp = msx-(d->x+hmar);
8907
8908 if(mp < 0)
8909 mp = 0;
8910
8911 if(mp > irange-hh)
8912 mp = irange-hh;
8913
8914 slpos = itofix(mp);
8915 slmax = fixdiv(slpos, slratio);
8916 newpos = fixtoi(slmax);
8917
8918 if(newpos != oldval)
8919 {
8920 d->d2 = newpos;
8921
8922 /* call callback function here */
8923 if(d->dp2 != NULL)
8924 {
8925 proc = (SLIDER_TYPE)(d->dp2);
8926 retval |= (*proc)(d->dp3, d->d2);
8927 }
8928
8929 GUI_EVENT(d, geCHANGE_VALUE);
8930 object_message(d, MSG_DRAW, 0);
8931 }
8932
8933 /* let other objects continue to animate */
8934 broadcast_dialog_message(MSG_IDLE, 0);
8935 update_hw_screen();
8936 }
8937
8938 break;
8939 }
8940
8941 return retval;
8942 }
8943
8944 // This is only used by jwin_check_proc and jwin_radio_proc.
8945 int32_t d_jwinbutton_proc(int32_t msg, DIALOG *d, int32_t)
8946 {
8947 BITMAP *gui_bmp;
8948 int32_t state1, state2;
8949 int32_t black;
8950 int32_t swap;
8951 int32_t g;
8952 ASSERT(d);
8953
8954 gui_bmp = screen;
8955
8956 switch(msg)
8957 {
8958 case MSG_DRAW:
8959 {
8960 if(d->flags & D_SELECTED)
8961 {
8962 g = 1;
8963 state1 = d->bg;
8964 state2 = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
8965 }
8966 else
8967 {
8968 g = 0;
8969 state1 = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
8970 state2 = d->bg;
8971 }
8972
8973 rectfill(gui_bmp, d->x+1+g, d->y+1+g, d->x+d->w-3+g, d->y+d->h-3+g, state2);
8974 rect(gui_bmp, d->x+g, d->y+g, d->x+d->w-2+g, d->y+d->h-2+g, state1);
8975 gui_textout_ex(gui_bmp, (char *)d->dp, d->x+d->w/2+g, d->y+d->h/2-text_height(font)/2+g, state1, -1, TRUE);
8976
8977 if(d->flags & D_SELECTED)
8978 {
8979 vline(gui_bmp, d->x, d->y, d->y+d->h-2, d->bg);
8980 hline(gui_bmp, d->x, d->y, d->x+d->w-2, d->bg);
8981 }
8982 else
8983 {
8984 black = makecol(0,0,0);
8985 vline(gui_bmp, d->x+d->w-1, d->y+1, d->y+d->h-2, black);
8986 hline(gui_bmp, d->x+1, d->y+d->h-1, d->x+d->w-1, black);
8987 }
8988
8989 if((d->flags & D_GOTFOCUS) &&
8990 (!(d->flags & D_SELECTED) || !(d->flags & D_EXIT)))
8991 dotted_rect(gui_bmp, d->x+1+g, d->y+1+g, d->x+d->w-3+g, d->y+d->h-3+g, state1, state2);
8992
8993 break;
8994 }
8995 case MSG_WANTFOCUS:
8996 return D_WANTFOCUS;
8997
8998 case MSG_KEY:
8999 {
9000 /* close dialog? */
9001 if(d->flags & D_EXIT)
9002 {
9003 return D_CLOSE;
9004 }
9005
9006 /* or just toggle */
9007 d->flags ^= D_SELECTED;
9008 GUI_EVENT(d, geTOGGLE);
9009 object_message(d, MSG_DRAW, 0);
9010 break;
9011 }
9012
9013 case MSG_CLICK:
9014 {
9015 /* what state was the button originally in? */
9016 state1 = d->flags & D_SELECTED;
9017
9018 swap = state1;
9019
9020 /* track the mouse until it is released */
9021 while(gui_mouse_b())
9022 {
9023 state2 = ((gui_mouse_x() >= d->x) && (gui_mouse_y() >= d->y) &&
9024 (gui_mouse_x() < d->x + d->w) && (gui_mouse_y() < d->y + d->h));
9025
9026 if(swap)
9027 state2 = !state2;
9028
9029 /* redraw? */
9030 bool should_redraw = false;
9031 if(((state1) && (!state2)) || ((state2) && (!state1)))
9032 {
9033 d->flags ^= D_SELECTED;
9034 GUI_EVENT(d, geTOGGLE);
9035 state1 = d->flags & D_SELECTED;
9036 object_message(d, MSG_DRAW, 0);
9037 should_redraw = true;
9038 }
9039
9040 /* let other objects continue to animate */
9041 int r = broadcast_dialog_message(MSG_IDLE, 0);
9042 if (r & D_REDRAWME) should_redraw = true;
9043
9044 if (should_redraw)
9045 {
9046 update_hw_screen();
9047 }
9048 }
9049
9050 if(d->dp3 != NULL)
9051 {
9052 //object_message(d, MSG_DRAW, 0);
9053 typedef int32_t (*funcType)(void);
9054 funcType func=reinterpret_cast<funcType>(d->dp3);
9055
9056 return func();
9057 }
9058
9059 /* should we close the dialog? */
9060 if(d->flags & D_EXIT)
9061 {
9062 return D_CLOSE;
9063 }
9064 break;
9065 }
9066 }
9067
9068 return D_O_K;
9069 }
9070
9071 //Misc bitmap drawing
9072 void draw_x(BITMAP* dest, int x1, int y1, int x2, int y2, int color)
9073 {
9074 line(dest, x1, y1, x2, y2, color);
9075 line(dest, x1, y2, x2, y1, color);
9076 }
9077
9078 void draw_check(BITMAP* dest, int x1, int y1, int x2, int y2, int c)
9079 {
9080 if(x2 < x1)
9081 zc_swap(x2,x1);
9082 if(y2 < y1)
9083 zc_swap(y2,y1);
9084 int x3 = ((x2-x1)/2)+x1;
9085 int y3 = y2-(x3-x1);
9086 line(dest, x1, y3, x3, y2, c);
9087 line(dest, x3, y2, x2, y1, c);
9088 }
9089
9090 void draw_checkerboard(BITMAP* dest, int x, int y, int sz, optional<int> cb_sz, int offx, int offy)
9091 {
9092 if(!cb_sz)
9093 cb_sz = sz/2;
9094 int ox = -x+offx, oy = -y+offy;
9095 ditherrectfill(dest, x, y, x+sz-1, y+sz-1, vc(CheckerCol1), dithChecker, *cb_sz, ox, oy, vc(CheckerCol2));
9096 }
9097
9098 int32_t d_vsync_proc(int32_t msg,DIALOG *d,int32_t c)
9099 {
9100 // This use to be what kept 60fps, but now render_timer_wait handles that.
9101 switch(msg)
9102 {
9103 case MSG_IDLE:
9104 {
9105 broadcast_dialog_message(MSG_VSYNC, c);
9106 if(d->dp)
9107 {
9108 int32_t ret = (*(std::function<int32_t()>*)d->dp)();
9109 switch(ret)
9110 {
9111 case ONTICK_EXIT:
9112 if(d->flags&D_NEW_GUI)
9113 close_new_gui_dlg(d);
9114 return D_EXIT;
9115 case ONTICK_CLOSE:
9116 if(d->flags&D_NEW_GUI)
9117 {
9118 //Simulate a GUI_EVENT for the window proc
9119 DIALOG* window = d-1;
9120 while(window->proc != jwin_win_proc) --window;
9121 int32_t ret = new_gui_event(window-1, geCLOSE);
9122 if(ret >= 0)
9123 return ret;
9124 }
9125 return D_EXIT;
9126 case ONTICK_REDRAW:
9127 return D_REDRAW;
9128 }
9129 }
9130 break;
9131 }
9132 }
9133
9134 return D_O_K;
9135 }
9136
9137 //
9138
9139 void draw_checkbox(BITMAP *dest,int x,int y,int sz,bool value)
9140 {
9141 draw_checkbox(dest,x,y,sz,sz,value);
9142 }
9143 void draw_checkbox(BITMAP *dest,int x,int y,int wid,int hei,bool value)
9144 {
9145 jwin_draw_frame(dest, x, y, wid, hei, FR_DEEP);
9146 rectfill(dest, x+2, y+2, x+wid-3, y+hei-3, jwin_pal[jcTEXTBG]);
9147
9148 if(value)
9149 {
9150 line(dest, x+2, y+2, x+wid-3, y+hei-3, jwin_pal[jcTEXTFG]);
9151 line(dest, x+2, y+hei-3, x+wid-3, y+2, jwin_pal[jcTEXTFG]);
9152 }
9153 }
9154 void draw_dis_checkbox(BITMAP *dest,int x,int y,int wid,int hei,bool value)
9155 {
9156 jwin_draw_frame(dest, x, y, wid, hei, FR_DEEP);
9157
9158 if(value)
9159 {
9160 line(dest, x+2, y+2, x+wid-3, y+hei-3, jwin_pal[jcTEXTFG]);
9161 line(dest, x+2, y+hei-3, x+wid-3, y+2, jwin_pal[jcTEXTFG]);
9162 }
9163 }
9164
9165 bool do_scheckbox(BITMAP *dest,int x,int y,int sz,int &value, int xoffs, int yoffs)
9166 {
9167 return do_checkbox(dest,x,y,sz,sz,value,xoffs,yoffs);
9168 }
9169 bool do_checkbox(BITMAP *dest,int x,int y,int wid,int hei,int &value, int xoffs, int yoffs)
9170 {
9171 bool over=false;
9172
9173 while(gui_mouse_b())
9174 {
9175 if(isinRect(gui_mouse_x()-xoffs,gui_mouse_y()-yoffs,x,y,x+wid-1,y+hei-1))
9176 {
9177 if(!over)
9178 {
9179 value=value?0:1;
9180 draw_checkbox(dest,x,y,wid,hei,value!=0);
9181 over=true;
9182 update_hw_screen();
9183 }
9184 }
9185 else
9186 {
9187 if(over)
9188 {
9189 value=value?0:1;
9190 draw_checkbox(dest,x,y,wid,hei,value!=0);
9191 over=false;
9192 update_hw_screen();
9193 }
9194 }
9195 rest(1);
9196 }
9197
9198 return over;
9199 }
9200 bool do_checkbox_tx(BITMAP *dest,int x,int y,int wid,int hei,int &value, int txtoffs, int xoffs, int yoffs)
9201 {
9202 bool over=false;
9203
9204 while(gui_mouse_b())
9205 {
9206 if(isinRect(gui_mouse_x()-xoffs,gui_mouse_y()-yoffs,x,y,x+wid-1+txtoffs,y+hei-1))
9207 {
9208 if(!over)
9209 {
9210 value=value?0:1;
9211 draw_checkbox(dest,x,y,wid,hei,value!=0);
9212 over=true;
9213 update_hw_screen();
9214 }
9215 }
9216 else
9217 {
9218 if(over)
9219 {
9220 value=value?0:1;
9221 draw_checkbox(dest,x,y,wid,hei,value!=0);
9222 over=false;
9223 update_hw_screen();
9224 }
9225 }
9226 rest(1);
9227 }
9228
9229 return over;
9230 }
9231
9232 //box_out stuff
9233 static int32_t box_x = 0;
9234 static int32_t box_y = 0;
9235 static bool box_active=false;
9236 static int32_t box_store_x = 0;
9237 439 static FONT *box_title_font=font;
9238 439 static FONT *box_message_font=font;
9239 static int32_t box_style=0;
9240 static int32_t box_titlebar_height=0;
9241 static int32_t box_message_height=0;
9242 static uint8_t box_text_scale=1;
9243 static int32_t box_w=304;
9244 static int32_t box_h=176;
9245 static int32_t box_l=8;
9246 static int32_t box_r=312;
9247 static int32_t box_t=32;
9248 static int32_t box_b=208;
9249 static bool box_log=true;
9250 static char box_log_msg[480];
9251 static int32_t box_msg_pos=0;
9252 static int32_t box_store_pos=0;
9253
9254 int32_t onSnapshot2()
9255 {
9256 char buf[20];
9257 int32_t num=0;
9258
9259 do
9260 {
9261 sprintf(buf, "zelda%03d.bmp", ++num);
9262 }
9263 while(num<999 && exists(buf));
9264
9265 PALETTE temppal;
9266 get_palette(temppal);
9267 BITMAP *tempbmp=create_bitmap_ex(8,screen->w, screen->h);
9268 blit(screen,tempbmp,0,0,0,0,screen->w,screen->h);
9269 save_bitmap(buf,screen,temppal);
9270 destroy_bitmap(tempbmp);
9271 return D_O_K;
9272 }
9273
9274 void set_default_box_size()
9275 {
9276 int32_t screen_w = screen->w;
9277 int32_t screen_h = screen->h;
9278
9279 box_w=MIN(512, screen_w-16);
9280 box_h=MIN(256, (screen_h-64)&0xFFF0);
9281
9282 box_l=(screen_w-box_w)/2;
9283 box_t=(screen_h-box_h)/2;
9284 box_r=box_l+box_w;
9285 box_b=box_t+box_h;
9286 }
9287 /* resizes the box */
9288 void set_box_size(int32_t w, int32_t h)
9289 {
9290 int32_t screen_w = zq_screen_w;
9291 int32_t screen_h = zq_screen_h;
9292
9293 if(w <= 0) w = 512;
9294 if(h <= 0) h = 256;
9295 box_w=MIN(w, screen_w-16);
9296 box_h=MIN(h, (screen_h-64)&0xFFF0);
9297
9298 box_l=(screen_w-box_w)/2;
9299 box_t=(screen_h-box_h)/2;
9300 box_r=box_l+box_w;
9301 box_b=box_t+box_h;
9302 }
9303
9304 /* starts outputting a progress message */
9305 9 void box_start(int32_t style, const char *title, FONT *title_font, FONT *message_font, bool log, int32_t w, int32_t h, uint8_t scale)
9306 {
9307
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (is_headless())
9308 9 return;
9309
9310 box_text_scale=scale;
9311 box_style=style;
9312 box_title_font=(title_font!=NULL)?title_font:font;
9313 box_message_font=(message_font!=NULL)?message_font:font;
9314 box_message_height=text_height(box_message_font)*scale;
9315 box_titlebar_height=title?text_height(box_title_font)+2:0;
9316 set_box_size(w,h);
9317 /*
9318 box_w=BOX_W;
9319 box_h=BOX_H;
9320 box_l=BOX_L;
9321 box_r=BOX_R;
9322 box_t=BOX_T;
9323 box_b=BOX_B;
9324 */
9325 box_log=log;
9326 memset(box_log_msg, 0, 480);
9327 box_msg_pos=0;
9328 box_store_pos=0;
9329
9330 if(!box_active)
9331 popup_zqdialog_start();
9332 jwin_draw_win(screen, box_l, box_t, box_r-box_l, box_b-box_t, FR_WIN);
9333
9334 if(title!=NULL)
9335 {
9336 zc_swap(font,box_title_font);
9337 jwin_draw_titlebar(screen, box_l+3, box_t+3, box_r-box_l-6, 18, title, false);
9338 zc_swap(font,box_title_font);
9339 box_titlebar_height=18;
9340 }
9341
9342
9343 box_store_x = box_x = box_y = 0;
9344 box_active = true;
9345 box_t+=box_titlebar_height;
9346 box_h-=box_titlebar_height;
9347 box_log=log;
9348 memset(box_log_msg, 0, 480);
9349 box_msg_pos=0;
9350 box_store_pos=0;
9351 9 }
9352
9353 /* outputs text to the progress message */
9354 30973 void box_out(const char *msg)
9355 {
9356
1/2
✓ Branch 0 taken 30973 times.
✗ Branch 1 not taken.
30973 string remainder = "";
9357
1/2
✓ Branch 0 taken 30973 times.
✗ Branch 1 not taken.
30973 string temp(msg);
9358
9359
1/2
✓ Branch 0 taken 30973 times.
✗ Branch 1 not taken.
30973 if(box_active)
9360 {
9361 //do primitive text wrapping
9362 uint32_t i;
9363 for(i=0; i<temp.size(); i++)
9364 {
9365 int32_t length = text_length(box_message_font,temp.substr(0,i).c_str())*box_text_scale;
9366
9367 if(length > box_r-box_l-16)
9368 {
9369 i = zc_max(i-1,0);
9370 break;
9371 }
9372 }
9373
9374 set_clip_rect(screen, box_l+8, box_t+1, box_r-8, box_b-1);
9375 if(box_text_scale == 1)
9376 textout_ex(screen, box_message_font, temp.substr(0,i).c_str(), box_l+8+box_x, box_t+(box_y+1)*box_message_height, gui_fg_color, gui_bg_color);
9377 else
9378 {
9379 int32_t length = text_length(box_message_font,temp.substr(0,i).c_str());
9380 BITMAP* tempbit = create_bitmap_ex(8, length, box_message_height);
9381 clear_bitmap(tempbit);
9382 textout_ex(tempbit, box_message_font, temp.substr(0,i).c_str(), 0, 0, gui_fg_color, gui_bg_color);
9383 stretch_blit(tempbit, screen, 0, 0, length, box_message_height/box_text_scale, box_l+8+box_x, box_t+(box_y+1)*box_message_height, length*box_text_scale, box_message_height);
9384 destroy_bitmap(tempbit);
9385 }
9386 set_clip_rect(screen, 0, 0, screen->w-1, screen->h-1);
9387 remainder = temp.substr(i,temp.size()-i);
9388 }
9389
9390
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30973 times.
30973 if(box_log)
9391 {
9392 30973 sprintf(box_log_msg+box_msg_pos, "%s", msg);
9393 30973 }
9394
9395
1/2
✓ Branch 0 taken 30973 times.
✗ Branch 1 not taken.
30973 box_x += text_length(box_message_font, msg);
9396 30973 box_msg_pos+=(int32_t)strlen(msg);
9397
9398
2/4
✓ Branch 0 taken 30973 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30973 times.
30973 if(remainder != "")
9399 {
9400 bool oldlog = box_log;
9401 box_log = false;
9402 box_eol();
9403 box_out(remainder.c_str());
9404 box_log = oldlog;
9405 }
9406
9407 // For web, always call update_hw_screen because it yields to the main thread,
9408 // which makes long running tasks like loading a quest not block the main thread,
9409 // which would make SFX sound awful on the title screen.
9410
3/6
✓ Branch 0 taken 30973 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30973 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 30973 times.
30973 if (box_active || is_web())
9411 update_hw_screen();
9412 30973 }
9413
9414 /* calls box_out, and box_eol for newlines */
9415 void box_out_nl(const char *msg)
9416 {
9417 string line;
9418 istringstream reader(msg);
9419 while (getline(reader, line))
9420 {
9421 box_out(line.c_str());
9422 box_eol();
9423 }
9424 }
9425
9426 /* remembers the current x position */
9427 492 void box_save_x()
9428 {
9429
1/2
✓ Branch 0 taken 492 times.
✗ Branch 1 not taken.
492 if(box_active)
9430 {
9431 box_store_x=box_x;
9432 }
9433
9434 492 box_store_pos=box_msg_pos;
9435 492 }
9436
9437 /* remembers the current x position */
9438 156 void box_load_x()
9439 {
9440
1/2
✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
156 if(box_active)
9441 {
9442 box_x=box_store_x;
9443 }
9444
9445 156 box_msg_pos=box_store_pos;
9446 156 }
9447
9448 /* outputs text to the progress message */
9449 16221 void box_eol()
9450 {
9451
1/2
✓ Branch 0 taken 16221 times.
✗ Branch 1 not taken.
16221 if(box_active)
9452 {
9453 box_x = 0;
9454 box_y++;
9455
9456 if((box_y+2)*box_message_height >= box_h)
9457 {
9458 blit(screen, screen, box_l+8, box_t+(box_message_height*2), box_l+8, box_t+(box_message_height), box_w-16, box_y*box_message_height);
9459 rectfill(screen, box_l+8, box_t+box_y*box_message_height, box_l+box_w-8, box_t+(box_y+1)*box_message_height, gui_bg_color);
9460 box_y--;
9461 }
9462 }
9463
9464 16221 box_msg_pos = 0;
9465
9466
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16221 times.
16221 if(box_log)
9467 {
9468 16221 al_trace("%s", box_log_msg);
9469 16221 al_trace("\n");
9470 16221 memset(box_log_msg, 0, 480);
9471 16221 }
9472
9473
1/2
✓ Branch 0 taken 16221 times.
✗ Branch 1 not taken.
16221 if (box_active)
9474 update_hw_screen();
9475 16221 }
9476
9477 /* ends output of a progress message */
9478 833 void box_end(bool pause)
9479 {
9480
1/2
✓ Branch 0 taken 833 times.
✗ Branch 1 not taken.
833 if(box_active)
9481 {
9482 if(pause)
9483 {
9484 box_eol();
9485 box_pause();
9486 }
9487
9488 box_active = false;
9489 popup_zqdialog_end();
9490 }
9491 833 }
9492
9493 /* pauses box output */
9494 void box_pause()
9495 {
9496 if(box_active)
9497 {
9498 box_save_x();
9499 box_out("-- press a key --");
9500
9501 while(gui_mouse_b()) rest(1);
9502 while(!(keypressed() || gui_mouse_b())) rest(1);
9503 while(gui_mouse_b()) rest(1);
9504
9505 clear_keybuf();
9506 box_load_x();
9507 }
9508 }
9509